diff --git a/api/tests/v1/create/compensation_create_post_body.json b/api/tests/v1/create/compensation_create_post_body.json index b0d21e83..865621a1 100644 --- a/api/tests/v1/create/compensation_create_post_body.json +++ b/api/tests/v1/create/compensation_create_post_body.json @@ -6,6 +6,7 @@ "title": "Test_compensation", "is_cef": false, "is_coherence_keeping": false, + "is_pik": false, "intervention": "MUST_BE_SET_IN_TEST", "before_states": [ ], diff --git a/api/tests/v1/create/ecoaccount_create_post_body.json b/api/tests/v1/create/ecoaccount_create_post_body.json index 8300277d..7550d8cd 100644 --- a/api/tests/v1/create/ecoaccount_create_post_body.json +++ b/api/tests/v1/create/ecoaccount_create_post_body.json @@ -5,6 +5,7 @@ "properties": { "title": "Test_ecoaccount", "deductable_surface": 10000.0, + "is_pik": false, "responsible": { "conservation_office": null, "conservation_file_number": null, diff --git a/api/tests/v1/create/ema_create_post_body.json b/api/tests/v1/create/ema_create_post_body.json index 4949b7ab..8b826661 100644 --- a/api/tests/v1/create/ema_create_post_body.json +++ b/api/tests/v1/create/ema_create_post_body.json @@ -4,6 +4,7 @@ ], "properties": { "title": "Test_ema", + "is_pik": false, "responsible": { "conservation_office": null, "conservation_file_number": null, diff --git a/api/tests/v1/get/test_api_get.py b/api/tests/v1/get/test_api_get.py index 953b0f69..0db58cbc 100644 --- a/api/tests/v1/get/test_api_get.py +++ b/api/tests/v1/get/test_api_get.py @@ -122,6 +122,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase): props = geojson["properties"] props["is_cef"] props["is_coherence_keeping"] + props["is_pik"] props["intervention"] props["intervention"]["id"] props["intervention"]["identifier"] diff --git a/api/tests/v1/update/compensation_update_put_body.json b/api/tests/v1/update/compensation_update_put_body.json index 57ad5ed4..4ae91ac7 100644 --- a/api/tests/v1/update/compensation_update_put_body.json +++ b/api/tests/v1/update/compensation_update_put_body.json @@ -46,6 +46,7 @@ "title": "TEST_compensation_CHANGED", "is_cef": true, "is_coherence_keeping": true, + "is_pik": true, "intervention": "CHANGE_BEFORE_RUN!!!", "before_states": [], "after_states": [], diff --git a/api/tests/v1/update/ecoaccount_update_put_body.json b/api/tests/v1/update/ecoaccount_update_put_body.json index ff636ff0..2b8235cb 100644 --- a/api/tests/v1/update/ecoaccount_update_put_body.json +++ b/api/tests/v1/update/ecoaccount_update_put_body.json @@ -45,6 +45,7 @@ "properties": { "title": "TEST_account_CHANGED", "deductable_surface": "100000.0", + "is_pik": true, "responsible": { "conservation_office": null, "conservation_file_number": "123-TEST", diff --git a/api/tests/v1/update/ema_update_put_body.json b/api/tests/v1/update/ema_update_put_body.json index cc835850..6c7adf68 100644 --- a/api/tests/v1/update/ema_update_put_body.json +++ b/api/tests/v1/update/ema_update_put_body.json @@ -52,6 +52,7 @@ "detail": "TEST_HANDLER_CHANGED" } }, + "is_pik": true, "before_states": [], "after_states": [], "actions": [], diff --git a/api/tests/v1/update/test_api_update.py b/api/tests/v1/update/test_api_update.py index bfc670bc..ff867e69 100644 --- a/api/tests/v1/update/test_api_update.py +++ b/api/tests/v1/update/test_api_update.py @@ -97,6 +97,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase): self.assertNotEqual(modified_on, self.compensation.modified) self.assertEqual(put_props["is_cef"], self.compensation.is_cef) self.assertEqual(put_props["is_coherence_keeping"], self.compensation.is_coherence_keeping) + self.assertEqual(put_props["is_pik"], self.compensation.is_pik) self.assertEqual(len(put_props["actions"]), self.compensation.actions.count()) self.assertEqual(len(put_props["before_states"]), self.compensation.before_states.count()) self.assertEqual(len(put_props["after_states"]), self.compensation.after_states.count()) diff --git a/api/utils/serializer/v1/compensation.py b/api/utils/serializer/v1/compensation.py index 24e499ef..89dbe0e6 100644 --- a/api/utils/serializer/v1/compensation.py +++ b/api/utils/serializer/v1/compensation.py @@ -34,6 +34,7 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa def _extend_properties_data(self, entry): self.properties_data["is_cef"] = entry.is_cef self.properties_data["is_coherence_keeping"] = entry.is_coherence_keeping + self.properties_data["is_pik"] = entry.is_pik self.properties_data["intervention"] = self.intervention_to_json(entry.intervention) self.properties_data["before_states"] = self._compensation_state_to_json(entry.before_states.all()) self.properties_data["after_states"] = self._compensation_state_to_json(entry.after_states.all()) @@ -113,6 +114,7 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa obj.title = properties["title"] obj.is_cef = properties["is_cef"] obj.is_coherence_keeping = properties["is_coherence_keeping"] + obj.is_pik = properties.get("is_pik", False) obj = self.set_intervention(obj, properties["intervention"], user) obj.geometry.save() @@ -149,6 +151,7 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa obj.title = properties["title"] obj.is_cef = properties["is_cef"] obj.is_coherence_keeping = properties["is_coherence_keeping"] + obj.is_pik = properties.get("is_pik", False) obj.modified = update_action obj.geometry.geom = self._create_geometry_from_json(json_model) obj.geometry.modified = update_action diff --git a/api/utils/serializer/v1/ecoaccount.py b/api/utils/serializer/v1/ecoaccount.py index 7fe4373d..106789f4 100644 --- a/api/utils/serializer/v1/ecoaccount.py +++ b/api/utils/serializer/v1/ecoaccount.py @@ -25,6 +25,7 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1, model = EcoAccount def _extend_properties_data(self, entry): + self.properties_data["is_pik"] = entry.is_pik self.properties_data["deductable_surface"] = entry.deductable_surface self.properties_data["deductable_surface_available"] = entry.deductable_surface - entry.get_deductions_surface() self.properties_data["responsible"] = self._responsible_to_json(entry.responsible) @@ -122,6 +123,7 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1, properties = json_model["properties"] obj.identifier = obj.generate_new_identifier() obj.title = properties["title"] + obj.is_pik = properties.get("is_pik", False) try: obj.deductable_surface = float(properties["deductable_surface"]) @@ -169,6 +171,7 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1, # Fill in data to objects properties = json_model["properties"] obj.title = properties["title"] + obj.is_pik = properties.get("is_pik", False) obj.deductable_surface = float(properties["deductable_surface"]) obj.modified = update_action obj.geometry.geom = self._create_geometry_from_json(json_model) diff --git a/api/utils/serializer/v1/ema.py b/api/utils/serializer/v1/ema.py index dfda7249..787a64b2 100644 --- a/api/utils/serializer/v1/ema.py +++ b/api/utils/serializer/v1/ema.py @@ -21,6 +21,7 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe model = Ema def _extend_properties_data(self, entry): + self.properties_data["is_pik"] = entry.is_pik self.properties_data["responsible"] = self._responsible_to_json(entry.responsible) self.properties_data["before_states"] = self._compensation_state_to_json(entry.before_states.all()) self.properties_data["after_states"] = self._compensation_state_to_json(entry.after_states.all()) @@ -104,6 +105,7 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe properties = json_model["properties"] obj.identifier = obj.generate_new_identifier() obj.title = properties["title"] + obj.is_pik = properties.get("is_pik", False) obj = self._set_responsibility(obj, properties["responsible"]) obj.geometry.save() @@ -141,6 +143,7 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe # Fill in data to objects properties = json_model["properties"] obj.title = properties["title"] + obj.is_pik = properties.get("is_pik", False) obj.modified = update_action obj.geometry.geom = self._create_geometry_from_json(json_model) obj.geometry.modified = update_action diff --git a/codelist/models.py b/codelist/models.py index de7a2100..8e5de0c9 100644 --- a/codelist/models.py +++ b/codelist/models.py @@ -65,24 +65,23 @@ class KonovaCode(models.Model): ret_val += ", " + self.parent.long_name return ret_val - def add_children(self): + def add_children(self, order_by: str = "long_name"): """ Adds all children (resurcively until leaf) as .children to the KonovaCode Returns: code (KonovaCode): The manipulated KonovaCode instance """ if self.is_leaf: - return None + return self children = KonovaCode.objects.filter( - code_lists__in=self.code_lists.all(), parent=self ).order_by( - "long_name" + order_by ) self.children = children for child in children: - child.add_children() + child.add_children(order_by) return self diff --git a/compensation/admin.py b/compensation/admin.py index a5cd1a88..2821a146 100644 --- a/compensation/admin.py +++ b/compensation/admin.py @@ -55,6 +55,7 @@ class CompensationAdmin(AbstractCompensationAdmin): return super().get_fields(request, obj) + [ "is_cef", "is_coherence_keeping", + "is_pik", "intervention", ] diff --git a/compensation/filters.py b/compensation/filters.py index b6377092..c9bf9b70 100644 --- a/compensation/filters.py +++ b/compensation/filters.py @@ -60,7 +60,7 @@ class CheckboxCompensationTableFilter(CheckboxTableFilter): if not value: return queryset.filter( Q(intervention__users__in=[self.user]) | # requesting user has access - Q(intervention__teams__users__in=[self.user]) + Q(intervention__teams__in=self.user.shared_teams) ).distinct() else: return queryset diff --git a/compensation/forms/forms.py b/compensation/forms/forms.py index 4e9e329e..8f28c5ff 100644 --- a/compensation/forms/forms.py +++ b/compensation/forms/forms.py @@ -160,7 +160,23 @@ class CoherenceCompensationFormMixin(forms.Form): ) -class NewCompensationForm(AbstractCompensationForm, CEFCompensationFormMixin, CoherenceCompensationFormMixin): +class PikCompensationFormMixin(forms.Form): + """ A form mixin, providing PIK compensation field + + """ + is_pik = forms.BooleanField( + label_suffix="", + label=_("Is PIK"), + help_text=_("Optionally: Whether this compensation is a compensation integrated in production?"), + required=False, + widget=forms.CheckboxInput() + ) + + +class NewCompensationForm(AbstractCompensationForm, + CEFCompensationFormMixin, + CoherenceCompensationFormMixin, + PikCompensationFormMixin): """ Form for creating new compensations. Can be initialized with an intervention id for preselecting the related intervention. @@ -191,6 +207,7 @@ class NewCompensationForm(AbstractCompensationForm, CEFCompensationFormMixin, Co "identifier", "title", "intervention", + "is_pik", "is_cef", "is_coherence_keeping", "comment", @@ -234,6 +251,7 @@ class NewCompensationForm(AbstractCompensationForm, CEFCompensationFormMixin, Co intervention = self.cleaned_data.get("intervention", None) is_cef = self.cleaned_data.get("is_cef", None) is_coherence_keeping = self.cleaned_data.get("is_coherence_keeping", None) + is_pik = self.cleaned_data.get("is_pik", None) comment = self.cleaned_data.get("comment", None) # Create log entry @@ -249,6 +267,7 @@ class NewCompensationForm(AbstractCompensationForm, CEFCompensationFormMixin, Co created=action, is_cef=is_cef, is_coherence_keeping=is_coherence_keeping, + is_pik=is_pik, geometry=geometry, comment=comment, ) @@ -281,6 +300,7 @@ class EditCompensationForm(NewCompensationForm): "intervention": self.instance.intervention, "is_cef": self.instance.is_cef, "is_coherence_keeping": self.instance.is_coherence_keeping, + "is_pik": self.instance.is_pik, "comment": self.instance.comment, } disabled_fields = [] @@ -297,6 +317,7 @@ class EditCompensationForm(NewCompensationForm): intervention = self.cleaned_data.get("intervention", None) is_cef = self.cleaned_data.get("is_cef", None) is_coherence_keeping = self.cleaned_data.get("is_coherence_keeping", None) + is_pik = self.cleaned_data.get("is_pik", None) comment = self.cleaned_data.get("comment", None) # Create log entry @@ -313,6 +334,7 @@ class EditCompensationForm(NewCompensationForm): self.instance.is_cef = is_cef self.instance.is_coherence_keeping = is_coherence_keeping self.instance.comment = comment + self.instance.is_pik = is_pik self.instance.modified = action self.instance.save() @@ -322,7 +344,7 @@ class EditCompensationForm(NewCompensationForm): return self.instance -class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMixin): +class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMixin, PikCompensationFormMixin): """ Form for creating eco accounts Inherits from basic AbstractCompensationForm and further form fields from CompensationResponsibleFormMixin @@ -363,6 +385,7 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix "registration_date", "surface", "conservation_file_number", + "is_pik", "handler_type", "handler_detail", "comment", @@ -392,6 +415,7 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix surface = self.cleaned_data.get("surface", None) conservation_office = self.cleaned_data.get("conservation_office", None) conservation_file_number = self.cleaned_data.get("conservation_file_number", None) + is_pik = self.cleaned_data.get("is_pik", None) comment = self.cleaned_data.get("comment", None) # Create log entry @@ -423,6 +447,7 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix created=action, geometry=geometry, comment=comment, + is_pik=is_pik, legal=legal ) acc.share_with_user(user) @@ -458,6 +483,7 @@ class EditEcoAccountForm(NewEcoAccountForm): "registration_date": reg_date, "conservation_office": self.instance.responsible.conservation_office, "conservation_file_number": self.instance.responsible.conservation_file_number, + "is_pik": self.instance.is_pik, "comment": self.instance.comment, } disabled_fields = [] @@ -478,6 +504,7 @@ class EditEcoAccountForm(NewEcoAccountForm): conservation_office = self.cleaned_data.get("conservation_office", None) conservation_file_number = self.cleaned_data.get("conservation_file_number", None) comment = self.cleaned_data.get("comment", None) + is_pik = self.cleaned_data.get("is_pik", None) # Create log entry action = UserActionLogEntry.get_edited_action(user) @@ -503,6 +530,7 @@ class EditEcoAccountForm(NewEcoAccountForm): self.instance.deductable_surface = surface self.instance.geometry = geometry self.instance.comment = comment + self.instance.is_pik = is_pik self.instance.modified = action self.instance.save() diff --git a/compensation/forms/modalForms.py b/compensation/forms/modalForms.py index 8404c7ad..581a7b3a 100644 --- a/compensation/forms/modalForms.py +++ b/compensation/forms/modalForms.py @@ -17,7 +17,8 @@ from codelist.models import KonovaCode from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID, \ CODELIST_COMPENSATION_ACTION_DETAIL_ID from compensation.models import CompensationDocument, EcoAccountDocument -from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple +from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple, \ + CompensationStateTreeRadioSelect from konova.contexts import BaseContext from konova.forms import BaseModalForm, NewDocumentModalForm, RemoveModalForm from konova.models import DeadlineType @@ -156,22 +157,12 @@ class NewStateModalForm(BaseModalForm): What has been on this area before changes/compensations have been applied and what will be the result ('after')? """ - biotope_type = forms.ModelChoiceField( + biotope_type = forms.ChoiceField( label=_("Biotope Type"), label_suffix="", required=True, help_text=_("Select the biotope type"), - queryset=KonovaCode.objects.filter( - is_archived=False, - is_leaf=True, - code_lists__in=[CODELIST_BIOTOPES_ID], - ), - widget=autocomplete.ModelSelect2( - url="codes-biotope-autocomplete", - attrs={ - "data-placeholder": _("Biotope Type"), - } - ), + widget=CompensationStateTreeRadioSelect(), ) biotope_extra = forms.ModelMultipleChoiceField( label=_("Biotope additional type"), @@ -209,6 +200,16 @@ class NewStateModalForm(BaseModalForm): super().__init__(*args, **kwargs) self.form_title = _("New state") self.form_caption = _("Insert data for the new state") + choices = KonovaCode.objects.filter( + code_lists__in=[CODELIST_BIOTOPES_ID], + is_archived=False, + is_leaf=True, + ).values_list("id", flat=True) + choices = [ + (choice, choice) + for choice in choices + ] + self.fields["biotope_type"].choices = choices def save(self, is_before_state: bool = False): state = self.instance.add_state(self, is_before_state) @@ -271,8 +272,9 @@ class EditCompensationStateModalForm(NewStateModalForm): self.state = kwargs.pop("state", None) super().__init__(*args, **kwargs) self.form_title = _("Edit state") + biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None form_data = { - "biotope_type": self.state.biotope_type, + "biotope_type": biotope_type_id, "biotope_extra": self.state.biotope_type_details.all(), "surface": self.state.surface, } @@ -280,7 +282,8 @@ class EditCompensationStateModalForm(NewStateModalForm): def save(self, is_before_state: bool = False): state = self.state - state.biotope_type = self.cleaned_data.get("biotope_type", None) + biotope_type_id = self.cleaned_data.get("biotope_type", None) + state.biotope_type = KonovaCode.objects.get(id=biotope_type_id) state.biotope_type_details.set(self.cleaned_data.get("biotope_extra", [])) state.surface = self.cleaned_data.get("surface", None) state.save() diff --git a/compensation/migrations/0007_auto_20220531_1245.py b/compensation/migrations/0007_auto_20220531_1245.py new file mode 100644 index 00000000..688ffb18 --- /dev/null +++ b/compensation/migrations/0007_auto_20220531_1245.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.3 on 2022-05-31 10:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('compensation', '0006_ecoaccount_teams'), + ] + + operations = [ + migrations.AddField( + model_name='compensation', + name='is_pik', + field=models.BooleanField(blank=True, default=False, help_text="Flag if compensation is a 'Produktonsintegrierte Kompensation'", null=True), + ), + migrations.AddField( + model_name='ecoaccount', + name='is_pik', + field=models.BooleanField(blank=True, default=False, help_text="Flag if compensation is a 'Produktonsintegrierte Kompensation'", null=True), + ), + ] diff --git a/compensation/models/compensation.py b/compensation/models/compensation.py index 3deff50a..2e42ff7a 100644 --- a/compensation/models/compensation.py +++ b/compensation/models/compensation.py @@ -8,6 +8,8 @@ Created on: 16.11.21 import shutil from django.contrib import messages + +from codelist.models import KonovaCode from user.models import User, Team from django.db import models, transaction from django.db.models import QuerySet, Sum @@ -142,8 +144,10 @@ class AbstractCompensation(BaseObject, GeoReferencedMixin): """ form_data = form.cleaned_data with transaction.atomic(): + biotope_type_id = form_data["biotope_type"] + code = KonovaCode.objects.get(id=biotope_type_id) state = CompensationState.objects.create( - biotope_type=form_data["biotope_type"], + biotope_type=code, surface=form_data["surface"], ) state_additional_types = form_data["biotope_extra"] @@ -253,7 +257,22 @@ class CoherenceMixin(models.Model): abstract = True -class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin): +class PikMixin(models.Model): + """ Provides PIK flag as Mixin + + """ + is_pik = models.BooleanField( + blank=True, + null=True, + default=False, + help_text="Flag if compensation is a 'Produktonsintegrierte Kompensation'" + ) + + class Meta: + abstract = True + + +class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin, PikMixin): """ Regular compensation, linked to an intervention """ diff --git a/compensation/models/eco_account.py b/compensation/models/eco_account.py index 6d95b399..3d48b691 100644 --- a/compensation/models/eco_account.py +++ b/compensation/models/eco_account.py @@ -17,14 +17,13 @@ from django.db.models import Sum, QuerySet from django.utils.translation import gettext_lazy as _ from compensation.managers import EcoAccountManager, EcoAccountDeductionManager -from compensation.models.compensation import AbstractCompensation +from compensation.models.compensation import AbstractCompensation, PikMixin from compensation.utils.quality import EcoAccountQualityChecker from konova.models import ShareableObjectMixin, RecordableObjectMixin, AbstractDocument, BaseResource, \ generate_document_file_upload_path -from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE -class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMixin): +class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMixin, PikMixin): """ An eco account is a kind of 'prepaid' compensation. It can be compared to an account that already has been filled with some kind of currency. From this account one is able to deduct currency for current projects. diff --git a/compensation/tables.py b/compensation/tables.py index 401a7416..1373f2cd 100644 --- a/compensation/tables.py +++ b/compensation/tables.py @@ -5,17 +5,15 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 01.12.20 """ -from user.models import User +from konova.utils.message_templates import DATA_IS_UNCHECKED, DATA_CHECKED_ON_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE from django.http import HttpRequest from django.template.loader import render_to_string from django.urls import reverse from django.utils.html import format_html -from django.utils.timezone import localtime from django.utils.translation import gettext_lazy as _ from compensation.filters import CompensationTableFilter, EcoAccountTableFilter from compensation.models import Compensation, EcoAccount -from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT from konova.utils.tables import BaseTable, TableRenderMixin import django_tables2 as tables @@ -111,16 +109,21 @@ class CompensationTable(BaseTable, TableRenderMixin): """ html = "" checked = value is not None - tooltip = _("Not checked yet") + tooltip = DATA_IS_UNCHECKED + previously_checked = record.intervention.get_last_checked_action() if checked: - value = value.timestamp - value = localtime(value) - checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Checked on {} by {}").format(checked_on, record.intervention.checked.user) + checked_on = value.get_timestamp_str_formatted() + tooltip = DATA_CHECKED_ON_TEMPLATE.format(checked_on, record.intervention.checked.user) html += self.render_checked_star( tooltip=tooltip, icn_filled=checked, ) + if previously_checked and not checked: + checked_on = previously_checked.get_timestamp_str_formatted() + tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(checked_on, previously_checked.user) + html += self.render_previously_checked_star( + tooltip=tooltip, + ) return format_html(html) def render_d(self, value, record: Compensation): @@ -159,9 +162,7 @@ class CompensationTable(BaseTable, TableRenderMixin): recorded = value is not None tooltip = _("Not recorded yet") if recorded: - value = value.timestamp - value = localtime(value) - on = value.strftime(DEFAULT_DATE_TIME_FORMAT) + on = value.get_timestamp_str_formatted() tooltip = _("Recorded on {} by {}").format(on, record.intervention.recorded.user) html += self.render_bookmark( tooltip=tooltip, @@ -179,8 +180,6 @@ class CompensationTable(BaseTable, TableRenderMixin): Returns: """ - if value is None: - value = User.objects.none() has_access = record.is_shared_with(self.user) html = self.render_icn( @@ -318,9 +317,7 @@ class EcoAccountTable(BaseTable, TableRenderMixin): checked = value is not None tooltip = _("Not recorded yet. Can not be used for deductions, yet.") if checked: - value = value.timestamp - value = localtime(value) - on = value.strftime(DEFAULT_DATE_TIME_FORMAT) + on = value.get_timestamp_str_formatted() tooltip = _("Recorded on {} by {}").format(on, record.recorded.user) html += self.render_bookmark( tooltip=tooltip, diff --git a/compensation/templates/compensation/detail/compensation/view.html b/compensation/templates/compensation/detail/compensation/view.html index 8e1b1267..5a125ccd 100644 --- a/compensation/templates/compensation/detail/compensation/view.html +++ b/compensation/templates/compensation/detail/compensation/view.html @@ -39,6 +39,16 @@ + + {% trans 'Is PIK' %} + + {% if obj.is_pik %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + {% trans 'Is CEF compensation' %} @@ -66,6 +76,11 @@ {% fa5_icon 'star' 'far' %} + {% if last_checked %} + + {% fa5_icon 'star' 'fas' %} + + {% endif %} {% else %} {% fa5_icon 'star' %} @@ -104,7 +119,7 @@ {% trans 'Shared with' %} - {% for team in obj.intervention.teams.all %} + {% for team in obj.intervention.shared_teams %} {% include 'user/includes/team_data_modal_button.html' %} {% endfor %}
@@ -119,7 +134,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/compensation/templates/compensation/detail/eco_account/view.html b/compensation/templates/compensation/detail/eco_account/view.html index 0eb354fe..432315a8 100644 --- a/compensation/templates/compensation/detail/eco_account/view.html +++ b/compensation/templates/compensation/detail/eco_account/view.html @@ -70,6 +70,16 @@ {% trans 'Action handler' %} {{obj.responsible.handler|default_if_none:""}} + + {% trans 'Is PIK' %} + + {% if obj.is_pik %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + {% trans 'Last modified' %} @@ -87,7 +97,7 @@ {% trans 'Shared with' %} - {% for team in obj.teams.all %} + {% for team in obj.shared_teams %} {% include 'user/includes/team_data_modal_button.html' %} {% endfor %}
@@ -101,7 +111,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/compensation/templates/compensation/report/compensation/report.html b/compensation/templates/compensation/report/compensation/report.html index 7088ff07..2be278aa 100644 --- a/compensation/templates/compensation/report/compensation/report.html +++ b/compensation/templates/compensation/report/compensation/report.html @@ -20,6 +20,36 @@ + + {% trans 'Is PIK' %} + + {% if obj.is_pik %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + + + {% trans 'Is CEF' %} + + {% if obj.is_cef %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + + + {% trans 'Is coherence keeping' %} + + {% if obj.is_coherence_keeping %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + {% trans 'Last modified' %} @@ -35,7 +65,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/compensation/templates/compensation/report/eco_account/report.html b/compensation/templates/compensation/report/eco_account/report.html index a3632ee2..e2147f69 100644 --- a/compensation/templates/compensation/report/eco_account/report.html +++ b/compensation/templates/compensation/report/eco_account/report.html @@ -20,6 +20,16 @@ {% trans 'Conservation office file number' %} {{obj.responsible.conservation_file_number|default_if_none:""}} + + {% trans 'Is PIK' %} + + {% if obj.is_pik %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + {% trans 'Deductions for' %} @@ -48,7 +58,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/compensation/tests/compensation/test_workflow.py b/compensation/tests/compensation/test_workflow.py index 570045f2..bba12334 100644 --- a/compensation/tests/compensation/test_workflow.py +++ b/compensation/tests/compensation/test_workflow.py @@ -50,10 +50,11 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase): test_id = self.create_dummy_string() test_title = self.create_dummy_string() test_geom = self.create_dummy_geometry() + geom_json = self.create_geojson(test_geom) post_data = { "identifier": test_id, "title": test_title, - "geom": test_geom.geojson, + "geom": geom_json, "intervention": self.intervention.id, } pre_creation_intervention_log_count = self.intervention.log.count() @@ -88,10 +89,11 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase): test_id = self.create_dummy_string() test_title = self.create_dummy_string() test_geom = self.create_dummy_geometry() + geom_json = self.create_geojson(test_geom) post_data = { "identifier": test_id, "title": test_title, - "geom": test_geom.geojson, + "geom": geom_json, } pre_creation_intervention_log_count = self.intervention.log.count() @@ -126,6 +128,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase): new_identifier = self.create_dummy_string() new_comment = self.create_dummy_string() new_geometry = MultiPolygon(srid=4326) # Create an empty geometry + geojson = self.create_geojson(new_geometry) check_on_elements = { self.compensation.title: new_title, @@ -140,7 +143,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase): "title": new_title, "intervention": self.intervention.id, # just keep the intervention as it is "comment": new_comment, - "geom": new_geometry.geojson, + "geom": geojson, } self.client_user.post(url, post_data) self.compensation.refresh_from_db() diff --git a/compensation/tests/ecoaccount/test_workflow.py b/compensation/tests/ecoaccount/test_workflow.py index bd6894ae..d1a3cf09 100644 --- a/compensation/tests/ecoaccount/test_workflow.py +++ b/compensation/tests/ecoaccount/test_workflow.py @@ -40,12 +40,13 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): test_id = self.create_dummy_string() test_title = self.create_dummy_string() test_geom = self.create_dummy_geometry() + geom_json = self.create_geojson(test_geom) test_deductable_surface = 1000 test_conservation_office = self.get_conservation_office_code() post_data = { "identifier": test_id, "title": test_title, - "geom": test_geom.geojson, + "geom": geom_json, "deductable_surface": test_deductable_surface, "conservation_office": test_conservation_office.id } diff --git a/compensation/views/compensation.py b/compensation/views/compensation.py index c3d3e2b5..31087ed7 100644 --- a/compensation/views/compensation.py +++ b/compensation/views/compensation.py @@ -23,7 +23,7 @@ from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED, DA CHECKED_RECORDED_RESET, COMPENSATION_ADDED_TEMPLATE, COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, \ COMPENSATION_STATE_REMOVED, COMPENSATION_STATE_ADDED, COMPENSATION_ACTION_REMOVED, COMPENSATION_ACTION_ADDED, \ DEADLINE_ADDED, DEADLINE_REMOVED, DOCUMENT_EDITED, COMPENSATION_STATE_EDITED, COMPENSATION_ACTION_EDITED, \ - DEADLINE_EDITED, RECORDED_BLOCKS_EDIT, PARAMS_INVALID + DEADLINE_EDITED, RECORDED_BLOCKS_EDIT, PARAMS_INVALID, DATA_CHECKED_PREVIOUSLY_TEMPLATE from konova.utils.user_checks import in_group @@ -217,8 +217,15 @@ def detail_view(request: HttpRequest, id: str): request = comp.set_status_messages(request) + last_checked = comp.intervention.get_last_checked_action() + last_checked_tooltip = "" + if last_checked: + last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(last_checked.get_timestamp_str_formatted(), last_checked.user) + context = { "obj": comp, + "last_checked": last_checked, + "last_checked_tooltip": last_checked_tooltip, "geom_form": geom_form, "parcels": parcels, "has_access": is_data_shared, diff --git a/ema/forms.py b/ema/forms.py index 91b8de19..a7e82c4f 100644 --- a/ema/forms.py +++ b/ema/forms.py @@ -12,14 +12,15 @@ from django.db import transaction from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ -from compensation.forms.forms import AbstractCompensationForm, CompensationResponsibleFormMixin +from compensation.forms.forms import AbstractCompensationForm, CompensationResponsibleFormMixin, \ + PikCompensationFormMixin from ema.models import Ema, EmaDocument from intervention.models import Responsibility, Handler from konova.forms import SimpleGeomForm, NewDocumentModalForm from user.models import UserActionLogEntry -class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin): +class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin, PikCompensationFormMixin): """ Form for creating new EMA objects. Inherits basic form fields from AbstractCompensationForm and additional from CompensationResponsibleFormMixin. @@ -31,6 +32,7 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin): "title", "conservation_office", "conservation_file_number", + "is_pik", "handler_type", "handler_detail", "comment", @@ -58,6 +60,7 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin): handler_detail = self.cleaned_data.get("handler_detail", None) conservation_office = self.cleaned_data.get("conservation_office", None) conservation_file_number = self.cleaned_data.get("conservation_file_number", None) + is_pik = self.cleaned_data.get("is_pik", None) comment = self.cleaned_data.get("comment", None) # Create log entry @@ -83,6 +86,7 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin): created=action, geometry=geometry, comment=comment, + is_pik=is_pik, ) # Add the creating user to the list of shared users @@ -116,6 +120,7 @@ class EditEmaForm(NewEmaForm): "conservation_office": self.instance.responsible.conservation_office, "conservation_file_number": self.instance.responsible.conservation_file_number, "comment": self.instance.comment, + "is_pik": self.instance.is_pik, } disabled_fields = [] self.load_initial_data( @@ -133,6 +138,7 @@ class EditEmaForm(NewEmaForm): conservation_office = self.cleaned_data.get("conservation_office", None) conservation_file_number = self.cleaned_data.get("conservation_file_number", None) comment = self.cleaned_data.get("comment", None) + is_pik = self.cleaned_data.get("is_pik", None) # Create log entry action = UserActionLogEntry.get_edited_action(user) @@ -152,6 +158,7 @@ class EditEmaForm(NewEmaForm): self.instance.title = title self.instance.geometry = geometry self.instance.comment = comment + self.instance.is_pik = is_pik self.instance.modified = action self.instance.save() diff --git a/ema/migrations/0004_ema_is_pik.py b/ema/migrations/0004_ema_is_pik.py new file mode 100644 index 00000000..534155a7 --- /dev/null +++ b/ema/migrations/0004_ema_is_pik.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.3 on 2022-05-31 10:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ema', '0003_ema_teams'), + ] + + operations = [ + migrations.AddField( + model_name='ema', + name='is_pik', + field=models.BooleanField(blank=True, default=False, help_text="Flag if compensation is a 'Produktonsintegrierte Kompensation'", null=True), + ), + ] diff --git a/ema/models/ema.py b/ema/models/ema.py index 983bdbd7..abec7c43 100644 --- a/ema/models/ema.py +++ b/ema/models/ema.py @@ -13,15 +13,14 @@ from django.db.models import QuerySet from django.http import HttpRequest from django.urls import reverse -from compensation.models import AbstractCompensation +from compensation.models import AbstractCompensation, PikMixin from ema.managers import EmaManager from ema.utils.quality import EmaQualityChecker from konova.models import AbstractDocument, generate_document_file_upload_path, RecordableObjectMixin, ShareableObjectMixin -from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE from konova.utils.message_templates import DATA_UNSHARED_EXPLANATION, DOCUMENT_REMOVED_TEMPLATE -class Ema(AbstractCompensation, ShareableObjectMixin, RecordableObjectMixin): +class Ema(AbstractCompensation, ShareableObjectMixin, RecordableObjectMixin, PikMixin): """ EMA = Ersatzzahlungsmaßnahme (compensation actions from payments) diff --git a/ema/tables.py b/ema/tables.py index 38d8a8c0..d26a31dc 100644 --- a/ema/tables.py +++ b/ema/tables.py @@ -115,7 +115,6 @@ class EmaTable(BaseTable, TableRenderMixin): ) return html - def render_r(self, value, record: Ema): """ Renders the registered column for a EMA @@ -130,9 +129,7 @@ class EmaTable(BaseTable, TableRenderMixin): recorded = value is not None tooltip = _("Not recorded yet") if recorded: - value = value.timestamp - value = localtime(value) - on = value.strftime(DEFAULT_DATE_TIME_FORMAT) + on = value.get_timestamp_str_formatted() tooltip = _("Recorded on {} by {}").format(on, record.recorded.user) html += self.render_bookmark( tooltip=tooltip, diff --git a/ema/templates/ema/detail/view.html b/ema/templates/ema/detail/view.html index 31d26e0b..16f31378 100644 --- a/ema/templates/ema/detail/view.html +++ b/ema/templates/ema/detail/view.html @@ -56,6 +56,16 @@ {% trans 'Action handler' %} {{obj.responsible.handler|default_if_none:""}} + + {% trans 'Is PIK' %} + + {% if obj.is_pik %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + {% trans 'Last modified' %} @@ -73,11 +83,11 @@ {% trans 'Shared with' %} - {% for team in obj.teams.all %} + {% for team in obj.shared_teams %} {% include 'user/includes/team_data_modal_button.html' %} {% endfor %}
- {% for user in obj.users.all %} + {% for user in obj.user.all %} {% include 'user/includes/contact_modal_button.html' %} {% endfor %} @@ -87,7 +97,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/ema/templates/ema/report/report.html b/ema/templates/ema/report/report.html index 43b64865..fd166596 100644 --- a/ema/templates/ema/report/report.html +++ b/ema/templates/ema/report/report.html @@ -20,6 +20,16 @@ {% trans 'Conservation office file number' %} {{obj.responsible.conservation_file_number|default_if_none:""}} + + {% trans 'Is PIK' %} + + {% if obj.is_pik %} + {% trans 'Yes' %} + {% else %} + {% trans 'No' %} + {% endif %} + + {% trans 'Last modified' %} @@ -35,7 +45,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/ema/tests/test_workflow.py b/ema/tests/test_workflow.py index ecc3f195..4391fdc6 100644 --- a/ema/tests/test_workflow.py +++ b/ema/tests/test_workflow.py @@ -41,11 +41,12 @@ class EmaWorkflowTestCase(BaseWorkflowTestCase): test_id = self.create_dummy_string() test_title = self.create_dummy_string() test_geom = self.create_dummy_geometry() + geom_json = self.create_geojson(test_geom) test_conservation_office = self.get_conservation_office_code() post_data = { "identifier": test_id, "title": test_title, - "geom": test_geom.geojson, + "geom": geom_json, "conservation_office": test_conservation_office.id } self.client_user.post(new_url, post_data) diff --git a/intervention/forms/forms.py b/intervention/forms/forms.py index b83c4fba..b85ba101 100644 --- a/intervention/forms/forms.py +++ b/intervention/forms/forms.py @@ -216,6 +216,10 @@ class NewInterventionForm(BaseForm): identifier = tmp_intervention.generate_new_identifier() self.initialize_form_field("identifier", identifier) + def is_valid(self): + super_valid_result = super().is_valid() + return super_valid_result + def save(self, user: User, geom_form: SimpleGeomForm): with transaction.atomic(): # Fetch data from cleaned POST values diff --git a/intervention/inputs.py b/intervention/inputs.py index 34fe0434..a08c0b74 100644 --- a/intervention/inputs.py +++ b/intervention/inputs.py @@ -1,6 +1,6 @@ from django import forms from codelist.models import KonovaCode -from codelist.settings import CODELIST_COMPENSATION_ACTION_ID +from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID class DummyFilterInput(forms.HiddenInput): @@ -38,7 +38,17 @@ class TreeCheckboxSelectMultiple(forms.CheckboxSelectMultiple): """ Provides multiple selection of parent-child data """ - template_name = "konova/widgets/checkbox-tree-select.html" + template_name = "konova/widgets/tree/checkbox/checkbox-tree-select.html" + + class meta: + abstract = True + + +class TreeRadioSelect(forms.RadioSelect): + """ Provides single selection of parent-child data + + """ + template_name = "konova/widgets/tree/radio/radio-tree-select.html" class meta: abstract = True @@ -68,6 +78,30 @@ class KonovaCodeTreeCheckboxSelectMultiple(TreeCheckboxSelectMultiple): return context +class KonovaCodeTreeRadioSelect(TreeRadioSelect): + """ Provides single selection of KonovaCode + + """ + filter = None + + def __init__(self, *args, **kwargs): + self.code_list = kwargs.pop("code_list", None) + self.filter = kwargs.pop("filter", {}) + super().__init__(*args, **kwargs) + + def get_context(self, name, value, attrs): + context = super().get_context(name, value, attrs) + codes = KonovaCode.objects.filter( + **self.filter, + ) + codes = [ + parent_code.add_children() + for parent_code in codes + ] + context["codes"] = codes + return context + + class CompensationActionTreeCheckboxSelectMultiple(KonovaCodeTreeCheckboxSelectMultiple): """ Provides multiple selection of CompensationActions @@ -79,4 +113,31 @@ class CompensationActionTreeCheckboxSelectMultiple(KonovaCodeTreeCheckboxSelectM self.filter = { "code_lists__in": [CODELIST_COMPENSATION_ACTION_ID], "parent": None, - } \ No newline at end of file + } + + +class CompensationStateTreeRadioSelect(KonovaCodeTreeRadioSelect): + """ Provides single selection of CompensationState + + """ + filter = None + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.filter = { + "code_lists__in": [CODELIST_BIOTOPES_ID], + "parent": None, + "is_archived": False, + } + + def get_context(self, name, value, attrs): + context = super().get_context(name, value, attrs) + codes = KonovaCode.objects.filter( + **self.filter, + ) + codes = [ + parent_code.add_children("short_name") + for parent_code in codes + ] + context["codes"] = codes + return context \ No newline at end of file diff --git a/intervention/tables.py b/intervention/tables.py index 8f312099..cff9391c 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -9,12 +9,11 @@ from django.http import HttpRequest from django.template.loader import render_to_string from django.urls import reverse from django.utils.html import format_html -from django.utils.timezone import localtime from django.utils.translation import gettext_lazy as _ from intervention.filters import InterventionTableFilter from intervention.models import Intervention -from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT, DEFAULT_DATE_FORMAT +from konova.utils.message_templates import DATA_CHECKED_ON_TEMPLATE, DATA_IS_UNCHECKED, DATA_CHECKED_PREVIOUSLY_TEMPLATE from konova.utils.tables import BaseTable, TableRenderMixin import django_tables2 as tables @@ -108,16 +107,21 @@ class InterventionTable(BaseTable, TableRenderMixin): """ html = "" checked = value is not None - tooltip = _("Not checked yet") + previously_checked = record.get_last_checked_action() + tooltip = DATA_IS_UNCHECKED if checked: - value = value.timestamp - value = localtime(value) - checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Checked on {} by {}").format(checked_on, record.checked.user) + checked_on = value.get_timestamp_str_formatted() + tooltip = DATA_CHECKED_ON_TEMPLATE.format(checked_on, record.checked.user) html += self.render_checked_star( tooltip=tooltip, icn_filled=checked, ) + if previously_checked and not checked: + checked_on = previously_checked.get_timestamp_str_formatted() + tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(checked_on, previously_checked.user) + html += self.render_previously_checked_star( + tooltip=tooltip, + ) return format_html(html) def render_d(self, value, record: Intervention): @@ -156,9 +160,7 @@ class InterventionTable(BaseTable, TableRenderMixin): checked = value is not None tooltip = _("Not recorded yet") if checked: - value = value.timestamp - value = localtime(value) - on = value.strftime(DEFAULT_DATE_TIME_FORMAT) + on = value.get_timestamp_str_formatted() tooltip = _("Recorded on {} by {}").format(on, record.recorded.user) html += self.render_bookmark( tooltip=tooltip, diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index 2d9628cd..1a596bb0 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -70,6 +70,11 @@ {% fa5_icon 'star' 'far' %} + {% if last_checked %} + + {% fa5_icon 'star' 'fas' %} + + {% endif %} {% else %} {% fa5_icon 'star' %} @@ -120,7 +125,7 @@ {% trans 'Shared with' %} - {% for team in obj.teams.all %} + {% for team in obj.shared_teams %} {% include 'user/includes/team_data_modal_button.html' %} {% endfor %}
@@ -134,7 +139,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/intervention/templates/intervention/report/report.html b/intervention/templates/intervention/report/report.html index 6e238fa2..1c1016d0 100644 --- a/intervention/templates/intervention/report/report.html +++ b/intervention/templates/intervention/report/report.html @@ -94,7 +94,9 @@
- {% include 'map/geom_form.html' %} +
+ {% include 'map/geom_form.html' %} +
{% include 'konova/includes/parcels/parcels.html' %} diff --git a/intervention/tests/test_workflow.py b/intervention/tests/test_workflow.py index 66770977..9124c3e8 100644 --- a/intervention/tests/test_workflow.py +++ b/intervention/tests/test_workflow.py @@ -46,6 +46,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase): test_id = self.create_dummy_string() test_title = self.create_dummy_string() test_geom = self.create_dummy_geometry() + geom_json = self.create_geojson(test_geom) new_url = reverse("intervention:new", args=()) @@ -59,7 +60,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase): post_data = { "identifier": test_id, "title": test_title, - "geom": test_geom.geojson, + "geom": geom_json, } response = self.client_user.post( new_url, diff --git a/intervention/views.py b/intervention/views.py index f882f214..36577202 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -19,7 +19,7 @@ from konova.utils.generators import generate_qr_code from konova.utils.message_templates import INTERVENTION_INVALID, FORM_INVALID, IDENTIFIER_REPLACED, \ CHECKED_RECORDED_RESET, DEDUCTION_REMOVED, DEDUCTION_ADDED, REVOCATION_ADDED, REVOCATION_REMOVED, \ COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, DEDUCTION_EDITED, REVOCATION_EDITED, DOCUMENT_EDITED, \ - RECORDED_BLOCKS_EDIT + RECORDED_BLOCKS_EDIT, DATA_CHECKED_PREVIOUSLY_TEMPLATE from konova.utils.user_checks import in_group @@ -265,15 +265,18 @@ def detail_view(request: HttpRequest, id: str): geom_form = SimpleGeomForm( instance=intervention, ) - - parcels = intervention.get_underlying_parcels() + last_checked = intervention.get_last_checked_action() + last_checked_tooltip = "" + if last_checked: + last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(last_checked.get_timestamp_str_formatted(), last_checked.user) context = { "obj": intervention, + "last_checked": last_checked, + "last_checked_tooltip": last_checked_tooltip, "compensations": compensations, "has_access": is_data_shared, "geom_form": geom_form, - "parcels": parcels, "is_default_member": in_group(_user, DEFAULT_GROUP), "is_zb_member": in_group(_user, ZB_GROUP), "is_ets_member": in_group(_user, ETS_GROUP), diff --git a/konova/admin.py b/konova/admin.py index 213120ea..b30f4b14 100644 --- a/konova/admin.py +++ b/konova/admin.py @@ -98,6 +98,18 @@ class DeadlineAdmin(admin.ModelAdmin): ] +class DeletableObjectMixinAdmin(admin.ModelAdmin): + class Meta: + abstract = True + + def restore_deleted_data(self, request, queryset): + queryset = queryset.filter( + deleted__isnull=False + ) + for entry in queryset: + entry.deleted.delete() + + class BaseResourceAdmin(admin.ModelAdmin): fields = [ "created", @@ -109,7 +121,7 @@ class BaseResourceAdmin(admin.ModelAdmin): ] -class BaseObjectAdmin(BaseResourceAdmin): +class BaseObjectAdmin(BaseResourceAdmin, DeletableObjectMixinAdmin): search_fields = [ "identifier", "title", @@ -126,13 +138,6 @@ class BaseObjectAdmin(BaseResourceAdmin): "deleted", ] - def restore_deleted_data(self, request, queryset): - queryset = queryset.filter( - deleted__isnull=False - ) - for entry in queryset: - entry.deleted.delete() - # Outcommented for a cleaner admin backend on production diff --git a/konova/autocompletes.py b/konova/autocompletes.py index e6036f02..fbd92f75 100644 --- a/konova/autocompletes.py +++ b/konova/autocompletes.py @@ -96,7 +96,9 @@ class ShareTeamAutocomplete(Select2QuerySetView): def get_queryset(self): if self.request.user.is_anonymous: return Team.objects.none() - qs = Team.objects.all() + qs = Team.objects.filter( + deleted__isnull=True + ) if self.q: # Due to privacy concerns only a full username match will return the proper user entry qs = qs.filter( @@ -108,6 +110,29 @@ class ShareTeamAutocomplete(Select2QuerySetView): return qs +class TeamAdminAutocomplete(Select2QuerySetView): + """ Autocomplete for share with teams + + """ + def get_queryset(self): + if self.request.user.is_anonymous: + return User.objects.none() + qs = User.objects.filter( + id__in=self.forwarded.get("members", []) + ).exclude( + id__in=self.forwarded.get("admins", []) + ) + if self.q: + # Due to privacy concerns only a full username match will return the proper user entry + qs = qs.filter( + name__icontains=self.q + ) + qs = qs.order_by( + "username" + ) + return qs + + class KonovaCodeAutocomplete(Select2GroupQuerySetView): """ Provides simple autocomplete functionality for codes diff --git a/konova/filters/mixins.py b/konova/filters/mixins.py index beb44dac..cfd9cc4c 100644 --- a/konova/filters/mixins.py +++ b/konova/filters/mixins.py @@ -305,7 +305,7 @@ class ShareableTableFilterMixin(django_filters.FilterSet): if not value: return queryset.filter( Q(users__in=[self.user]) | # requesting user has access - Q(teams__users__in=[self.user]) + Q(teams__in=self.user.shared_teams) ).distinct() else: return queryset diff --git a/konova/forms.py b/konova/forms.py index a1e14478..0a341e0c 100644 --- a/konova/forms.py +++ b/konova/forms.py @@ -5,18 +5,20 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 16.11.20 """ - +import json from abc import abstractmethod from bootstrap_modal_forms.forms import BSModalForm from bootstrap_modal_forms.utils import is_ajax from django import forms from django.contrib import messages +from django.contrib.gis import gdal from django.db.models.fields.files import FieldFile +from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP from user.models import User -from django.contrib.gis.forms import OSMWidget, MultiPolygonField -from django.contrib.gis.geos import MultiPolygon +from django.contrib.gis.forms import MultiPolygonField +from django.contrib.gis.geos import MultiPolygon, Polygon from django.db import transaction from django.http import HttpRequest, HttpResponseRedirect from django.shortcuts import render @@ -272,41 +274,85 @@ class SimpleGeomForm(BaseForm): """ A geometry form for rendering geometry read-only using a widget """ + read_only = True geom = MultiPolygonField( - srid=DEFAULT_SRID, + srid=DEFAULT_SRID_RLP, label=_("Geometry"), help_text=_(""), label_suffix="", required=False, disabled=False, - widget=OSMWidget( - attrs={ - "map_width": 600, - "map_height": 400, - # default_zoom defines the nearest possible zoom level from which the JS automatically - # zooms out if geometry requires a larger view port. So define a larger range for smaller geometries - "default_zoom": 25, - } - ) ) def __init__(self, *args, **kwargs): - read_only = kwargs.pop("read_only", True) + self.read_only = kwargs.pop("read_only", True) super().__init__(*args, **kwargs) # Initialize geometry try: geom = self.instance.geometry.geom self.empty = geom.empty + + if self.empty: + raise AttributeError + + geojson = self.instance.geometry.as_feature_collection(srid=DEFAULT_SRID_RLP) + geom = json.dumps(geojson) except AttributeError: # If no geometry exists for this form, we simply set the value to None and zoom to the maximum level - geom = None + geom = "" self.empty = True - self.fields["geom"].widget.attrs["default_zoom"] = 1 self.initialize_form_field("geom", geom) - if read_only: - self.fields["geom"].disabled = True + + def is_valid(self): + super().is_valid() + is_valid = True + + # Get geojson from form + geom = self.data["geom"] + if geom is None or len(geom) == 0: + # empty geometry is a valid geometry + return is_valid + geom = json.loads(geom) + + # Write submitted data back into form field to make sure invalid geometry + # will be rendered again on failed submit + self.initialize_form_field("geom", self.data["geom"]) + + # Read geojson into gdal geometry + # HINT: This can be simplified if the geojson format holds data in epsg:4326 (GDAL provides direct creation for + # this case) + features = [] + features_json = geom.get("features", []) + for feature in features_json: + g = gdal.OGRGeometry(json.dumps(feature.get("geometry", feature)), srs=DEFAULT_SRID_RLP) + if g.geom_type not in ["Polygon", "MultiPolygon"]: + self.add_error("geom", _("Only surfaces allowed. Points or lines must be buffered.")) + is_valid = False + return is_valid + + polygon = Polygon.from_ewkt(g.ewkt) + is_valid = polygon.valid + if not is_valid: + self.add_error("geom", polygon.valid_reason) + return is_valid + + features.append(polygon) + form_geom = MultiPolygon(srid=DEFAULT_SRID_RLP) + for feature in features: + form_geom = form_geom.union(feature) + + # Make sure to convert into a MultiPolygon. Relevant if a single Polygon is provided. + if form_geom.geom_type != "MultiPolygon": + form_geom = MultiPolygon(form_geom, srid=DEFAULT_SRID_RLP) + + # Write unioned Multipolygon into cleaned data + if self.cleaned_data is None: + self.cleaned_data = {} + self.cleaned_data["geom"] = form_geom.ewkt + + return is_valid def save(self, action: UserActionLogEntry): """ Saves the form's geometry diff --git a/konova/migrations/0010_auto_20220420_1034.py b/konova/migrations/0010_auto_20220420_1034.py new file mode 100644 index 00000000..c916ff54 --- /dev/null +++ b/konova/migrations/0010_auto_20220420_1034.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.3 on 2022-04-20 08:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('konova', '0009_auto_20220411_1004'), + ] + + operations = [ + migrations.AddConstraint( + model_name='parcel', + constraint=models.UniqueConstraint(fields=('district', 'municipal', 'parcel_group', 'flr', 'flrstck_nnr', 'flrstck_zhlr'), name='Unique parcel constraint'), + ), + ] diff --git a/konova/migrations/0011_auto_20220420_1101.py b/konova/migrations/0011_auto_20220420_1101.py new file mode 100644 index 00000000..b402818e --- /dev/null +++ b/konova/migrations/0011_auto_20220420_1101.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.3 on 2022-04-20 09:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('konova', '0010_auto_20220420_1034'), + ] + + operations = [ + migrations.AddConstraint( + model_name='district', + constraint=models.UniqueConstraint(fields=('key', 'name'), name='Unique district constraint'), + ), + migrations.AddConstraint( + model_name='municipal', + constraint=models.UniqueConstraint(fields=('key', 'name', 'district'), name='Unique municipal constraint'), + ), + migrations.AddConstraint( + model_name='parcelgroup', + constraint=models.UniqueConstraint(fields=('key', 'name', 'municipal'), name='Unique parcel group constraint'), + ), + ] diff --git a/konova/models/geometry.py b/konova/models/geometry.py index 283f8508..b996feb7 100644 --- a/konova/models/geometry.py +++ b/konova/models/geometry.py @@ -5,11 +5,15 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 15.11.21 """ +import json + from django.contrib.gis.db.models import MultiPolygonField -from django.db import models +from django.contrib.gis.geos import Polygon +from django.db import models, transaction from django.utils import timezone from konova.models import BaseResource, UuidModel +from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP from konova.utils.wfs.spatial import ParcelWFSFetcher @@ -96,6 +100,7 @@ class Geometry(BaseResource): objs += set_objs return objs + @transaction.atomic def update_parcels(self): """ Updates underlying parcel information @@ -152,6 +157,7 @@ class Geometry(BaseResource): underlying_parcels.append(parcel_obj) # Update the linked parcels + self.parcels.clear() self.parcels.set(underlying_parcels) # Set the calculated_on intermediate field, so this related data will be found on lookups @@ -172,7 +178,6 @@ class Geometry(BaseResource): Returns: parcels (QuerySet): The related parcels as queryset """ - parcels = self.parcels.filter( parcelintersection__calculated_on__isnull=False, ).prefetch_related( @@ -184,6 +189,44 @@ class Geometry(BaseResource): return parcels + def count_underlying_parcels(self): + """ Getter for number of underlying parcels + + Returns: + + """ + num_parcels = self.parcels.filter( + parcelintersection__calculated_on__isnull=False, + ).count() + return num_parcels + + def as_feature_collection(self, srid=DEFAULT_SRID_RLP): + """ Returns a FeatureCollection structure holding all polygons of the MultiPolygon as single features + + This method is used to convert a single MultiPolygon into multiple Polygons, which can be used as separated + features in the NETGIS map client. + + Args: + srid (int): The spatial reference system identifier to be transformed to + + Returns: + geojson (dict): The FeatureCollection json (as dict) + """ + geom = self.geom + geom.transform(ct=srid) + + polygons = [] + for coords in geom.coords: + p = Polygon(coords[0], srid=geom.srid) + polygons.append(p) + geojson = { + "type": "FeatureCollection", + "features": [ + json.loads(x.geojson) for x in polygons + ] + } + return geojson + class GeometryConflict(UuidModel): """ diff --git a/konova/models/object.py b/konova/models/object.py index a1cff71b..b468932a 100644 --- a/konova/models/object.py +++ b/konova/models/object.py @@ -87,25 +87,15 @@ class BaseResource(UuidModel): super().delete() -class BaseObject(BaseResource): - """ - A basic object model, which specifies BaseResource. +class DeletableObjectMixin(models.Model): + """ Wraps deleted field and related functionality - Mainly used for intervention, compensation, ecoaccount """ - identifier = models.CharField(max_length=1000, null=True, blank=True) - title = models.CharField(max_length=1000, null=True, blank=True) deleted = models.ForeignKey("user.UserActionLogEntry", on_delete=models.SET_NULL, null=True, blank=True, related_name='+') - comment = models.TextField(null=True, blank=True) - log = models.ManyToManyField("user.UserActionLogEntry", blank=True, help_text="Keeps all user actions of an object", editable=False) class Meta: abstract = True - @abstractmethod - def set_status_messages(self, request: HttpRequest): - raise NotImplementedError - def mark_as_deleted(self, user, send_mail: bool = True): """ Mark an entry as deleted @@ -140,6 +130,25 @@ class BaseObject(BaseResource): self.save() + +class BaseObject(BaseResource, DeletableObjectMixin): + """ + A basic object model, which specifies BaseResource. + + Mainly used for intervention, compensation, ecoaccount + """ + identifier = models.CharField(max_length=1000, null=True, blank=True) + title = models.CharField(max_length=1000, null=True, blank=True) + comment = models.TextField(null=True, blank=True) + log = models.ManyToManyField("user.UserActionLogEntry", blank=True, help_text="Keeps all user actions of an object", editable=False) + + class Meta: + abstract = True + + @abstractmethod + def set_status_messages(self, request: HttpRequest): + raise NotImplementedError + def mark_as_edited(self, performing_user, request: HttpRequest = None, edit_comment: str = None): """ In case the object or a related object changed the log history needs to be updated @@ -408,6 +417,20 @@ class CheckableObjectMixin(models.Model): self.log.add(action) return action + def get_last_checked_action(self): + """ Getter for the most recent checked action on the log + + Returns: + previously_checked (UserActionLogEntry): The most recent checked action + """ + from user.models import UserAction + previously_checked = self.log.filter( + action=UserAction.CHECKED + ).order_by( + "-timestamp" + ).first() + return previously_checked + class ShareableObjectMixin(models.Model): # Users having access on this object @@ -470,8 +493,8 @@ class ShareableObjectMixin(models.Model): Returns: """ - directly_shared = self.users.filter(id=user.id).exists() - team_shared = self.teams.filter( + directly_shared = self.shared_users.filter(id=user.id).exists() + team_shared = self.shared_teams.filter( users__in=[user] ).exists() is_shared = directly_shared or team_shared @@ -608,7 +631,9 @@ class ShareableObjectMixin(models.Model): Returns: teams (QuerySet) """ - return self.teams.all() + return self.teams.filter( + deleted__isnull=True + ) @abstractmethod def get_share_url(self): @@ -652,10 +677,21 @@ class GeoReferencedMixin(models.Model): Returns: parcels (Iterable): An empty list or a Queryset """ + result = [] if self.geometry is not None: - return self.geometry.get_underlying_parcels() - else: - return [] + result = self.geometry.get_underlying_parcels() + return result + + def count_underlying_parcels(self): + """ Getter for number of underlying parcels + + Returns: + + """ + result = 0 + if self.geometry is not None: + result = self.geometry.count_underlying_parcels() + return result def set_geometry_conflict_message(self, request: HttpRequest): if self.geometry is None: diff --git a/konova/models/parcel.py b/konova/models/parcel.py index f74b7af9..cc91e006 100644 --- a/konova/models/parcel.py +++ b/konova/models/parcel.py @@ -39,7 +39,17 @@ class District(UuidModel, AdministrativeSpatialReference): """ The model District refers to "Kreis" """ - pass + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=[ + "key", + "name", + ], + name="Unique district constraint" + ) + ] class Municipal(UuidModel, AdministrativeSpatialReference): @@ -53,6 +63,18 @@ class Municipal(UuidModel, AdministrativeSpatialReference): blank=True, ) + class Meta: + constraints = [ + models.UniqueConstraint( + fields=[ + "key", + "name", + "district", + ], + name="Unique municipal constraint" + ) + ] + class ParcelGroup(UuidModel, AdministrativeSpatialReference): """ The model ParcelGroup refers to "Gemarkung", which is defined as a loose group of parcels @@ -65,6 +87,18 @@ class ParcelGroup(UuidModel, AdministrativeSpatialReference): blank=True, ) + class Meta: + constraints = [ + models.UniqueConstraint( + fields=[ + "key", + "name", + "municipal", + ], + name="Unique parcel group constraint" + ) + ] + class Parcel(UuidModel): """ The Parcel model holds administrative data on covered properties. @@ -106,6 +140,21 @@ class Parcel(UuidModel): ) updated_on = models.DateTimeField(auto_now_add=True) + class Meta: + constraints = [ + models.UniqueConstraint( + fields=[ + "district", + "municipal", + "parcel_group", + "flr", + "flrstck_nnr", + "flrstck_zhlr", + ], + name="Unique parcel constraint" + ) + ] + def __str__(self): return f"{self.parcel_group} | {self.flr} | {self.flrstck_zhlr} | {self.flrstck_nnr}" diff --git a/konova/static/css/konova.css b/konova/static/css/konova.css index 7e7f3fd1..ed797046 100644 --- a/konova/static/css/konova.css +++ b/konova/static/css/konova.css @@ -262,4 +262,13 @@ Similar to bootstraps 'shadow-lg' padding-left: 2em; } - */ \ No newline at end of file + */ +.collapse-icn > i{ + transition: all 0.3s ease; +} +.collapsed .collapse-icn > i{ + transform: rotate(-90deg); +} +.tree-label.badge{ + font-size: 90%; +} \ No newline at end of file diff --git a/konova/sub_settings/django_settings.py b/konova/sub_settings/django_settings.py index cbbf7fc5..54c35bee 100644 --- a/konova/sub_settings/django_settings.py +++ b/konova/sub_settings/django_settings.py @@ -46,8 +46,8 @@ ALLOWED_HOSTS = [ LOGIN_URL = "/login/" # Session settings -#SESSION_COOKIE_AGE = 30 * 60 # 30 minutes -#SESSION_SAVE_EVERY_REQUEST = True +SESSION_COOKIE_AGE = 60 * 60 # 60 minutes +SESSION_SAVE_EVERY_REQUEST = True # Application definition @@ -192,6 +192,8 @@ STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, "static") STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'konova/static'), + os.path.join(BASE_DIR, 'templates/map/client'), # NETGIS map client files + os.path.join(BASE_DIR, 'templates/map/client/libs'), # NETGIS map client files ] # DJANGO DEBUG TOOLBAR diff --git a/konova/templates/konova/includes/comment_card.html b/konova/templates/konova/includes/comment_card.html index a84f378e..d9ea59bc 100644 --- a/konova/templates/konova/includes/comment_card.html +++ b/konova/templates/konova/includes/comment_card.html @@ -6,7 +6,7 @@ {% if obj.comment %} -
+
diff --git a/konova/templates/konova/includes/parcels/parcel_table_frame.html b/konova/templates/konova/includes/parcels/parcel_table_frame.html index e3292004..21b75b76 100644 --- a/konova/templates/konova/includes/parcels/parcel_table_frame.html +++ b/konova/templates/konova/includes/parcels/parcel_table_frame.html @@ -5,6 +5,11 @@ {% trans 'Parcels can not be calculated, since no geometry is given.' %} {% else %} +
+

+ {{num_parcels}} + {% trans 'Parcels found' %}

+
diff --git a/konova/templates/konova/widgets/checkbox-tree-select-content.html b/konova/templates/konova/widgets/tree/checkbox/checkbox-tree-select-content.html similarity index 53% rename from konova/templates/konova/widgets/checkbox-tree-select-content.html rename to konova/templates/konova/widgets/tree/checkbox/checkbox-tree-select-content.html index 9bf57253..84f97ece 100644 --- a/konova/templates/konova/widgets/checkbox-tree-select-content.html +++ b/konova/templates/konova/widgets/tree/checkbox/checkbox-tree-select-content.html @@ -2,18 +2,23 @@ {% for code in codes %}
-
- {% include 'konova/widgets/checkbox-tree-select-content.html' %} + {% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
\ No newline at end of file diff --git a/konova/tests/test_autocompletes.py b/konova/tests/test_autocompletes.py index 95a3508d..1533d572 100644 --- a/konova/tests/test_autocompletes.py +++ b/konova/tests/test_autocompletes.py @@ -72,6 +72,7 @@ class AutocompleteTestCase(BaseTestCase): "codes-conservation-office-autocomplete", "share-user-autocomplete", "share-team-autocomplete", + "team-admin-autocomplete", ] for test in tests: self.client.login(username=self.superuser.username, password=self.superuser_pw) diff --git a/konova/tests/test_views.py b/konova/tests/test_views.py index 28b3f8a2..73029f96 100644 --- a/konova/tests/test_views.py +++ b/konova/tests/test_views.py @@ -6,9 +6,11 @@ Created on: 26.10.21 """ import datetime +import json from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID from ema.models import Ema +from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP from user.models import User, Team from django.contrib.auth.models import Group from django.contrib.gis.geos import MultiPolygon, Polygon @@ -272,7 +274,6 @@ class BaseTestCase(TestCase): team = Team.objects.get_or_create( name="Testteam", description="Testdescription", - admin=self.superuser, )[0] team.users.add(self.superuser) @@ -287,8 +288,28 @@ class BaseTestCase(TestCase): """ polygon = Polygon.from_bbox((7.592449, 50.359385, 7.593382, 50.359874)) polygon.srid = 4326 - polygon = polygon.transform(3857, clone=True) - return MultiPolygon(polygon, srid=3857) # 3857 is the default srid used for MultiPolygonField in the form + polygon = polygon.transform(DEFAULT_SRID_RLP, clone=True) + return MultiPolygon(polygon, srid=DEFAULT_SRID_RLP) + + def create_geojson(self, geometry): + """ Creates a default structure including geojson from a geometry + + Args: + geometry (): + + Returns: + + """ + geom_json = { + "features": [ + { + "type": "Feature", + "geometry": json.loads(geometry.geojson), + } + ] + } + geom_json = json.dumps(geom_json) + return geom_json def create_dummy_handler(self) -> Handler: """ Creates a Handler @@ -410,11 +431,12 @@ class BaseTestCase(TestCase): return if geom1.srid != geom2.srid: + tolerance = 0.001 # Due to prior possible transformation of any of these geometries, we need to make sure there exists a # transformation from one coordinate system into the other, which is valid geom1_t = geom1.transform(geom2.srid, clone=True) geom2_t = geom2.transform(geom1.srid, clone=True) - self.assertTrue(geom1_t.equals(geom2) or geom2_t.equals(geom1)) + self.assertTrue(geom1_t.equals_exact(geom2, tolerance) or geom2_t.equals_exact(geom1, tolerance)) else: self.assertTrue(geom1.equals(geom2)) diff --git a/konova/urls.py b/konova/urls.py index 00386a11..e0126832 100644 --- a/konova/urls.py +++ b/konova/urls.py @@ -21,10 +21,10 @@ from konova.autocompletes import EcoAccountAutocomplete, \ InterventionAutocomplete, CompensationActionCodeAutocomplete, BiotopeCodeAutocomplete, LawCodeAutocomplete, \ RegistrationOfficeCodeAutocomplete, ConservationOfficeCodeAutocomplete, ProcessTypeCodeAutocomplete, \ ShareUserAutocomplete, BiotopeExtraCodeAutocomplete, CompensationActionDetailCodeAutocomplete, \ - ShareTeamAutocomplete, HandlerCodeAutocomplete + ShareTeamAutocomplete, HandlerCodeAutocomplete, TeamAdminAutocomplete from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG from konova.sso.sso import KonovaSSOClient -from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content +from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content, map_client_proxy_view sso_client = KonovaSSOClient(SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY) urlpatterns = [ @@ -42,6 +42,7 @@ urlpatterns = [ path('api/', include("api.urls")), path('geom//parcels/', get_geom_parcels, name="geometry-parcels"), path('geom//parcels/', get_geom_parcels_content, name="geometry-parcels-content"), + path('client/proxy', map_client_proxy_view, name="map-client-proxy"), # Autocomplete paths for all apps path("atcmplt/eco-accounts", EcoAccountAutocomplete.as_view(), name="accounts-autocomplete"), @@ -57,6 +58,7 @@ urlpatterns = [ path("atcmplt/codes/handler", HandlerCodeAutocomplete.as_view(), name="codes-handler-autocomplete"), path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"), path("atcmplt/share/t", ShareTeamAutocomplete.as_view(), name="share-team-autocomplete"), + path("atcmplt/team/admin", TeamAdminAutocomplete.as_view(), name="team-admin-autocomplete"), ] if DEBUG: diff --git a/konova/utils/message_templates.py b/konova/utils/message_templates.py index e062005a..f6e3ca18 100644 --- a/konova/utils/message_templates.py +++ b/konova/utils/message_templates.py @@ -81,3 +81,8 @@ GEOMETRY_CONFLICT_WITH_TEMPLATE = _("Geometry conflict detected with {}") # INTERVENTION INTERVENTION_HAS_REVOCATIONS_TEMPLATE = _("This intervention has {} revocations") + +# CHECKED +DATA_CHECKED_ON_TEMPLATE = _("Checked on {} by {}") +DATA_CHECKED_PREVIOUSLY_TEMPLATE = _("Data has changed since last check on {} by {}") +DATA_IS_UNCHECKED = _("Current data not checked yet") diff --git a/konova/utils/tables.py b/konova/utils/tables.py index d3a0406b..d7468725 100644 --- a/konova/utils/tables.py +++ b/konova/utils/tables.py @@ -112,6 +112,17 @@ class BaseTable(tables.tables.Table): icon ) + def render_previously_checked_star(self, tooltip: str = None): + """ + Returns a star icon for a check action in the past + """ + icon = "fas fa-star rlp-gd-inv" + return format_html( + "", + tooltip, + icon + ) + def render_bookmark(self, tooltip: str = None, icn_filled: bool = False): """ Returns a bookmark icon diff --git a/konova/utils/wfs/spatial.py b/konova/utils/wfs/spatial.py index 2f1452d6..e6cae847 100644 --- a/konova/utils/wfs/spatial.py +++ b/konova/utils/wfs/spatial.py @@ -11,7 +11,7 @@ from json import JSONDecodeError from time import sleep import requests -from django.contrib.gis.db.models.functions import AsGML, Transform +from django.contrib.gis.db.models.functions import AsGML, Transform, MakeValid from requests.auth import HTTPDigestAuth from konova.settings import DEFAULT_SRID_RLP, PARCEL_WFS_USER, PARCEL_WFS_PW, PROXIES @@ -91,7 +91,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher): ).annotate( transformed=Transform(srid=filter_srid, expression="geom") ).annotate( - gml=AsGML('transformed') + gml=AsGML(MakeValid('transformed')) ).first().gml spatial_filter = f"<{geometry_operation}>{self.geometry_property_name}{geom_gml}" return spatial_filter diff --git a/konova/views.py b/konova/views.py index 97cb7d82..4fadf6a0 100644 --- a/konova/views.py +++ b/konova/views.py @@ -5,9 +5,12 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 16.11.20 """ +import json + +import requests from django.contrib.auth import logout from django.contrib.auth.decorators import login_required -from django.http import HttpRequest, HttpResponse +from django.http import HttpRequest, HttpResponse, JsonResponse from django.shortcuts import redirect, render, get_object_or_404 from django.template.loader import render_to_string from django.utils import timezone @@ -135,12 +138,14 @@ def get_geom_parcels(request: HttpRequest, id: str): municipals = Municipal.objects.filter(id__in=municipals) rpp = 100 + num_all_parcels = parcels.count() parcels = parcels[:rpp] next_page = 1 if len(parcels) < rpp: next_page = None context = { + "num_parcels": num_all_parcels, "parcels": parcels, "municipals": municipals, "geom_id": str(id), @@ -220,3 +225,26 @@ def get_500_view(request: HttpRequest): """ context = BaseContext.context return render(request, "500.html", context, status=500) + + +@login_required +def map_client_proxy_view(request: HttpRequest): + """ Provides proxy functionality for NETGIS map client. + + Used for fetching content of a provided url + + Args: + request (HttpRequest): The incoming request + + Returns: + + """ + url = request.META.get("QUERY_STRING") + response = requests.get(url) + body = json.loads(response.content) + if response.status_code != 200: + return JsonResponse({ + "status_code": response.status_code, + "content": body, + }) + return JsonResponse(body) diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 45575064..885f0b9d 100644 Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 35ee2c5c..93238630 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -3,9 +3,9 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # -#: compensation/filters.py:123 compensation/forms/modalForms.py:36 -#: compensation/forms/modalForms.py:47 compensation/forms/modalForms.py:63 -#: compensation/forms/modalForms.py:358 compensation/forms/modalForms.py:466 +#: compensation/filters.py:123 compensation/forms/modalForms.py:37 +#: compensation/forms/modalForms.py:48 compensation/forms/modalForms.py:64 +#: compensation/forms/modalForms.py:362 compensation/forms/modalForms.py:470 #: intervention/forms/forms.py:54 intervention/forms/forms.py:174 #: intervention/forms/forms.py:186 intervention/forms/modalForms.py:150 #: intervention/forms/modalForms.py:163 intervention/forms/modalForms.py:176 @@ -18,15 +18,15 @@ #: konova/filters/mixins.py:277 konova/filters/mixins.py:323 #: konova/filters/mixins.py:361 konova/filters/mixins.py:362 #: konova/filters/mixins.py:393 konova/filters/mixins.py:394 -#: konova/forms.py:177 konova/forms.py:278 konova/forms.py:349 -#: konova/forms.py:393 konova/forms.py:403 konova/forms.py:416 -#: konova/forms.py:428 konova/forms.py:446 user/forms.py:42 +#: konova/forms.py:179 konova/forms.py:281 konova/forms.py:395 +#: konova/forms.py:439 konova/forms.py:449 konova/forms.py:462 +#: konova/forms.py:474 konova/forms.py:492 user/forms.py:42 #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-04-21 14:16+0200\n" +"POT-Creation-Date: 2022-05-31 13:05+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -61,11 +61,11 @@ msgid "Select the responsible office" msgstr "Verantwortliche Stelle" #: analysis/forms.py:58 compensation/forms/forms.py:88 -#: compensation/forms/forms.py:118 compensation/forms/forms.py:183 +#: compensation/forms/forms.py:118 compensation/forms/forms.py:199 #: intervention/forms/forms.py:64 intervention/forms/forms.py:81 #: intervention/forms/forms.py:97 intervention/forms/forms.py:113 #: intervention/forms/forms.py:154 intervention/forms/modalForms.py:49 -#: intervention/forms/modalForms.py:63 user/forms.py:196 +#: intervention/forms/modalForms.py:63 user/forms.py:196 user/forms.py:260 msgid "Click for selection" msgstr "Auswählen..." @@ -77,7 +77,7 @@ msgstr "Bericht generieren" msgid "Select a timespan and the desired conservation office" msgstr "Wählen Sie die Zeitspanne und die gewünschte Eintragungsstelle" -#: analysis/forms.py:69 konova/forms.py:225 +#: analysis/forms.py:69 konova/forms.py:227 msgid "Continue" msgstr "Weiter" @@ -97,7 +97,7 @@ msgstr "" #: analysis/templates/analysis/reports/includes/eco_account/amount.html:3 #: analysis/templates/analysis/reports/includes/intervention/amount.html:3 #: analysis/templates/analysis/reports/includes/old_data/amount.html:3 -#: compensation/forms/modalForms.py:450 +#: compensation/forms/modalForms.py:454 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:34 #: intervention/templates/intervention/detail/includes/deductions.html:31 msgid "Amount" @@ -138,11 +138,11 @@ msgstr "Zuständigkeitsbereich" #: analysis/templates/analysis/reports/includes/intervention/amount.html:17 #: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:8 #: analysis/templates/analysis/reports/includes/intervention/laws.html:17 -#: compensation/tables.py:40 -#: compensation/templates/compensation/detail/compensation/view.html:64 -#: intervention/tables.py:39 +#: compensation/tables.py:38 +#: compensation/templates/compensation/detail/compensation/view.html:74 +#: intervention/tables.py:38 #: intervention/templates/intervention/detail/view.html:68 -#: user/models/user_action.py:20 +#: user/models/user_action.py:21 msgid "Checked" msgstr "Geprüft" @@ -154,14 +154,14 @@ msgstr "Geprüft" #: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9 #: analysis/templates/analysis/reports/includes/intervention/laws.html:20 #: analysis/templates/analysis/reports/includes/old_data/amount.html:18 -#: compensation/tables.py:46 compensation/tables.py:220 -#: compensation/templates/compensation/detail/compensation/view.html:78 +#: compensation/tables.py:44 compensation/tables.py:219 +#: compensation/templates/compensation/detail/compensation/view.html:93 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31 #: compensation/templates/compensation/detail/eco_account/view.html:45 #: ema/tables.py:44 ema/templates/ema/detail/view.html:35 -#: intervention/tables.py:45 -#: intervention/templates/intervention/detail/view.html:82 -#: user/models/user_action.py:21 +#: intervention/tables.py:44 +#: intervention/templates/intervention/detail/view.html:87 +#: user/models/user_action.py:22 msgid "Recorded" msgstr "Verzeichnet" @@ -198,7 +198,7 @@ msgid "Other registration office" msgstr "Andere Zulassungsbehörden" #: analysis/templates/analysis/reports/includes/compensation/card_compensation.html:11 -#: compensation/tables.py:67 +#: compensation/tables.py:65 #: intervention/templates/intervention/detail/includes/compensations.html:8 #: intervention/templates/intervention/report/report.html:45 msgid "Compensations" @@ -215,7 +215,7 @@ msgstr "Abbuchungen" #: analysis/templates/analysis/reports/includes/eco_account/deductions.html:9 #: analysis/templates/analysis/reports/includes/eco_account/deductions.html:11 -#: compensation/forms/modalForms.py:195 +#: compensation/forms/modalForms.py:187 #: compensation/templates/compensation/detail/compensation/includes/states-after.html:36 #: compensation/templates/compensation/detail/compensation/includes/states-before.html:36 #: compensation/templates/compensation/detail/eco_account/includes/states-after.html:36 @@ -227,7 +227,7 @@ msgid "Surface" msgstr "Fläche" #: analysis/templates/analysis/reports/includes/intervention/card_intervention.html:10 -#: intervention/tables.py:66 +#: intervention/tables.py:65 msgid "Interventions" msgstr "Eingriffe" @@ -248,7 +248,7 @@ msgid "Compensation" msgstr "Kompensation" #: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:21 -#: compensation/forms/modalForms.py:76 +#: compensation/forms/modalForms.py:77 msgid "Payment" msgstr "Zahlung" @@ -285,8 +285,8 @@ msgid "Type" msgstr "Typ" #: analysis/templates/analysis/reports/includes/old_data/amount.html:24 -#: compensation/tables.py:89 intervention/forms/modalForms.py:375 -#: intervention/forms/modalForms.py:382 intervention/tables.py:88 +#: compensation/tables.py:87 intervention/forms/modalForms.py:375 +#: intervention/forms/modalForms.py:382 intervention/tables.py:87 #: intervention/templates/intervention/detail/view.html:19 #: konova/templates/konova/includes/quickstart/interventions.html:4 #: templates/navbars/navbar.html:22 @@ -294,7 +294,7 @@ msgid "Intervention" msgstr "Eingriff" #: analysis/templates/analysis/reports/includes/old_data/amount.html:34 -#: compensation/tables.py:264 +#: compensation/tables.py:263 #: compensation/templates/compensation/detail/eco_account/view.html:20 #: intervention/forms/modalForms.py:348 intervention/forms/modalForms.py:355 #: konova/templates/konova/includes/quickstart/ecoaccounts.html:4 @@ -314,9 +314,9 @@ msgstr "Vor" msgid "Show only unrecorded" msgstr "Nur unverzeichnete anzeigen" -#: compensation/forms/forms.py:32 compensation/tables.py:25 -#: compensation/tables.py:195 ema/tables.py:29 intervention/forms/forms.py:28 -#: intervention/tables.py:24 +#: compensation/forms/forms.py:32 compensation/tables.py:23 +#: compensation/tables.py:194 ema/tables.py:29 intervention/forms/forms.py:28 +#: intervention/tables.py:23 #: intervention/templates/intervention/detail/includes/compensations.html:30 msgid "Identifier" msgstr "Kennung" @@ -326,8 +326,8 @@ msgstr "Kennung" msgid "Generated automatically" msgstr "Automatisch generiert" -#: compensation/forms/forms.py:44 compensation/tables.py:30 -#: compensation/tables.py:200 +#: compensation/forms/forms.py:44 compensation/tables.py:28 +#: compensation/tables.py:199 #: compensation/templates/compensation/detail/compensation/includes/documents.html:28 #: compensation/templates/compensation/detail/compensation/view.html:32 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:28 @@ -337,12 +337,12 @@ msgstr "Automatisch generiert" #: ema/tables.py:34 ema/templates/ema/detail/includes/documents.html:28 #: ema/templates/ema/detail/view.html:31 #: ema/templates/ema/report/report.html:12 intervention/forms/forms.py:40 -#: intervention/tables.py:29 +#: intervention/tables.py:28 #: intervention/templates/intervention/detail/includes/compensations.html:33 #: intervention/templates/intervention/detail/includes/documents.html:28 #: intervention/templates/intervention/detail/view.html:31 #: intervention/templates/intervention/report/report.html:12 -#: konova/forms.py:392 +#: konova/forms.py:438 msgid "Title" msgstr "Bezeichnung" @@ -350,12 +350,12 @@ msgstr "Bezeichnung" msgid "An explanatory name" msgstr "Aussagekräftiger Titel" -#: compensation/forms/forms.py:50 ema/forms.py:50 ema/forms.py:108 +#: compensation/forms/forms.py:50 ema/forms.py:52 ema/forms.py:112 msgid "Compensation XY; Location ABC" msgstr "Kompensation XY; Flur ABC" -#: compensation/forms/forms.py:57 compensation/forms/modalForms.py:62 -#: compensation/forms/modalForms.py:357 compensation/forms/modalForms.py:465 +#: compensation/forms/forms.py:57 compensation/forms/modalForms.py:63 +#: compensation/forms/modalForms.py:361 compensation/forms/modalForms.py:469 #: compensation/templates/compensation/detail/compensation/includes/actions.html:35 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:34 #: compensation/templates/compensation/detail/compensation/includes/documents.html:34 @@ -369,11 +369,11 @@ msgstr "Kompensation XY; Flur ABC" #: intervention/templates/intervention/detail/includes/documents.html:34 #: intervention/templates/intervention/detail/includes/payments.html:34 #: intervention/templates/intervention/detail/includes/revocation.html:38 -#: konova/forms.py:427 konova/templates/konova/includes/comment_card.html:16 +#: konova/forms.py:473 konova/templates/konova/includes/comment_card.html:16 msgid "Comment" msgstr "Kommentar" -#: compensation/forms/forms.py:59 compensation/forms/modalForms.py:467 +#: compensation/forms/forms.py:59 compensation/forms/modalForms.py:471 #: intervention/forms/forms.py:200 msgid "Additional comment" msgstr "Zusätzlicher Kommentar" @@ -431,118 +431,131 @@ msgid "" "Optionally: Whether this compensation is a coherence keeping compensation?" msgstr "Optional: Handelt es sich um eine Kohärenzsicherungsmaßnahme?" -#: compensation/forms/forms.py:174 +#: compensation/forms/forms.py:169 +#: compensation/templates/compensation/detail/compensation/view.html:44 +#: compensation/templates/compensation/detail/eco_account/view.html:75 +#: ema/templates/ema/detail/view.html:61 +msgid "Is PIK" +msgstr "Ist PIK Maßnahme" + +#: compensation/forms/forms.py:170 +msgid "" +"Optionally: Whether this compensation is a compensation integrated in " +"production?" +msgstr "Optional: Handelt es sich um eine produktionsintegrierte Kompensation?" + +#: compensation/forms/forms.py:190 #: compensation/templates/compensation/detail/compensation/view.html:36 #: compensation/templates/compensation/report/compensation/report.html:16 msgid "compensates intervention" msgstr "kompensiert Eingriff" -#: compensation/forms/forms.py:176 +#: compensation/forms/forms.py:192 msgid "Select the intervention for which this compensation compensates" msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist" -#: compensation/forms/forms.py:202 compensation/views/compensation.py:110 +#: compensation/forms/forms.py:219 compensation/views/compensation.py:110 msgid "New compensation" msgstr "Neue Kompensation" -#: compensation/forms/forms.py:273 +#: compensation/forms/forms.py:292 msgid "Edit compensation" msgstr "Bearbeite Kompensation" -#: compensation/forms/forms.py:334 compensation/utils/quality.py:84 +#: compensation/forms/forms.py:356 compensation/utils/quality.py:84 msgid "Available Surface" msgstr "Verfügbare Fläche" -#: compensation/forms/forms.py:337 +#: compensation/forms/forms.py:359 msgid "The amount that can be used for deductions" msgstr "Die für Abbuchungen zur Verfügung stehende Menge" -#: compensation/forms/forms.py:346 +#: compensation/forms/forms.py:368 #: compensation/templates/compensation/detail/eco_account/view.html:67 #: compensation/utils/quality.py:72 msgid "Agreement date" msgstr "Vereinbarungsdatum" -#: compensation/forms/forms.py:348 +#: compensation/forms/forms.py:370 msgid "When did the parties agree on this?" msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?" -#: compensation/forms/forms.py:373 compensation/views/eco_account.py:108 +#: compensation/forms/forms.py:396 compensation/views/eco_account.py:108 msgid "New Eco-Account" msgstr "Neues Ökokonto" -#: compensation/forms/forms.py:382 +#: compensation/forms/forms.py:405 msgid "Eco-Account XY; Location ABC" msgstr "Ökokonto XY; Flur ABC" -#: compensation/forms/forms.py:442 +#: compensation/forms/forms.py:467 msgid "Edit Eco-Account" msgstr "Ökokonto bearbeiten" -#: compensation/forms/modalForms.py:37 +#: compensation/forms/modalForms.py:38 msgid "in Euro" msgstr "in Euro" -#: compensation/forms/modalForms.py:46 +#: compensation/forms/modalForms.py:47 #: intervention/templates/intervention/detail/includes/payments.html:31 msgid "Due on" msgstr "Fällig am" -#: compensation/forms/modalForms.py:49 +#: compensation/forms/modalForms.py:50 msgid "Due on which date" msgstr "Zahlung wird an diesem Datum erwartet" -#: compensation/forms/modalForms.py:64 compensation/forms/modalForms.py:359 -#: intervention/forms/modalForms.py:177 konova/forms.py:429 +#: compensation/forms/modalForms.py:65 compensation/forms/modalForms.py:363 +#: intervention/forms/modalForms.py:177 konova/forms.py:475 msgid "Additional comment, maximum {} letters" msgstr "Zusätzlicher Kommentar, maximal {} Zeichen" -#: compensation/forms/modalForms.py:77 +#: compensation/forms/modalForms.py:78 msgid "Add a payment for intervention '{}'" msgstr "Neue Ersatzzahlung zu Eingriff '{}' hinzufügen" -#: compensation/forms/modalForms.py:97 +#: compensation/forms/modalForms.py:98 msgid "If there is no date you can enter, please explain why." msgstr "Falls Sie kein Datum angeben können, erklären Sie bitte weshalb." -#: compensation/forms/modalForms.py:116 +#: compensation/forms/modalForms.py:117 #: intervention/templates/intervention/detail/includes/payments.html:59 msgid "Edit payment" msgstr "Zahlung bearbeiten" -#: compensation/forms/modalForms.py:159 compensation/forms/modalForms.py:171 +#: compensation/forms/modalForms.py:161 msgid "Biotope Type" msgstr "Biotoptyp" -#: compensation/forms/modalForms.py:162 +#: compensation/forms/modalForms.py:164 msgid "Select the biotope type" msgstr "Biotoptyp wählen" -#: compensation/forms/modalForms.py:176 compensation/forms/modalForms.py:188 +#: compensation/forms/modalForms.py:168 compensation/forms/modalForms.py:180 msgid "Biotope additional type" msgstr "Zusatzbezeichnung" -#: compensation/forms/modalForms.py:179 +#: compensation/forms/modalForms.py:171 msgid "Select an additional biotope type" msgstr "Zusatzbezeichnung wählen" -#: compensation/forms/modalForms.py:198 intervention/forms/modalForms.py:366 +#: compensation/forms/modalForms.py:190 intervention/forms/modalForms.py:366 msgid "in m²" msgstr "" -#: compensation/forms/modalForms.py:209 +#: compensation/forms/modalForms.py:201 msgid "New state" msgstr "Neuer Zustand" -#: compensation/forms/modalForms.py:210 +#: compensation/forms/modalForms.py:202 msgid "Insert data for the new state" msgstr "Geben Sie die Daten des neuen Zustandes ein" -#: compensation/forms/modalForms.py:217 konova/forms.py:227 +#: compensation/forms/modalForms.py:219 konova/forms.py:229 msgid "Object removed" msgstr "Objekt entfernt" -#: compensation/forms/modalForms.py:272 +#: compensation/forms/modalForms.py:274 #: compensation/templates/compensation/detail/compensation/includes/states-after.html:62 #: compensation/templates/compensation/detail/compensation/includes/states-before.html:62 #: compensation/templates/compensation/detail/eco_account/includes/states-after.html:62 @@ -552,15 +565,15 @@ msgstr "Objekt entfernt" msgid "Edit state" msgstr "Zustand bearbeiten" -#: compensation/forms/modalForms.py:329 +#: compensation/forms/modalForms.py:333 msgid "Deadline Type" msgstr "Fristart" -#: compensation/forms/modalForms.py:332 +#: compensation/forms/modalForms.py:336 msgid "Select the deadline type" msgstr "Fristart wählen" -#: compensation/forms/modalForms.py:341 +#: compensation/forms/modalForms.py:345 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:31 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:31 #: ema/templates/ema/detail/includes/deadlines.html:31 @@ -568,30 +581,30 @@ msgstr "Fristart wählen" msgid "Date" msgstr "Datum" -#: compensation/forms/modalForms.py:344 +#: compensation/forms/modalForms.py:348 msgid "Select date" msgstr "Datum wählen" -#: compensation/forms/modalForms.py:371 +#: compensation/forms/modalForms.py:375 msgid "New deadline" msgstr "Neue Frist" -#: compensation/forms/modalForms.py:372 +#: compensation/forms/modalForms.py:376 msgid "Insert data for the new deadline" msgstr "Geben Sie die Daten der neuen Frist ein" -#: compensation/forms/modalForms.py:385 +#: compensation/forms/modalForms.py:389 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:59 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:57 #: ema/templates/ema/detail/includes/deadlines.html:57 msgid "Edit deadline" msgstr "Frist/Termin bearbeiten" -#: compensation/forms/modalForms.py:413 +#: compensation/forms/modalForms.py:417 msgid "Action Type" msgstr "Maßnahmentyp" -#: compensation/forms/modalForms.py:416 +#: compensation/forms/modalForms.py:420 msgid "" "An action can consist of multiple different action types. All the selected " "action types are expected to be performed according to the amount and unit " @@ -601,35 +614,35 @@ msgstr "" "hier gewählten Einträge sollen mit der weiter unten angegebenen Einheit und " "Menge umgesetzt werden. " -#: compensation/forms/modalForms.py:421 compensation/forms/modalForms.py:433 +#: compensation/forms/modalForms.py:425 compensation/forms/modalForms.py:437 msgid "Action Type detail" msgstr "Zusatzmerkmal" -#: compensation/forms/modalForms.py:424 +#: compensation/forms/modalForms.py:428 msgid "Select the action type detail" msgstr "Zusatzmerkmal wählen" -#: compensation/forms/modalForms.py:438 +#: compensation/forms/modalForms.py:442 msgid "Unit" msgstr "Einheit" -#: compensation/forms/modalForms.py:441 +#: compensation/forms/modalForms.py:445 msgid "Select the unit" msgstr "Einheit wählen" -#: compensation/forms/modalForms.py:453 +#: compensation/forms/modalForms.py:457 msgid "Insert the amount" msgstr "Menge eingeben" -#: compensation/forms/modalForms.py:478 +#: compensation/forms/modalForms.py:482 msgid "New action" msgstr "Neue Maßnahme" -#: compensation/forms/modalForms.py:479 +#: compensation/forms/modalForms.py:483 msgid "Insert data for the new action" msgstr "Geben Sie die Daten der neuen Maßnahme ein" -#: compensation/forms/modalForms.py:503 +#: compensation/forms/modalForms.py:507 #: compensation/templates/compensation/detail/compensation/includes/actions.html:68 #: compensation/templates/compensation/detail/eco_account/includes/actions.html:67 #: ema/templates/ema/detail/includes/actions.html:65 @@ -675,70 +688,62 @@ msgstr "" "Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen " "wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!" -#: compensation/tables.py:35 compensation/tables.py:205 ema/tables.py:39 -#: intervention/tables.py:34 konova/filters/mixins.py:98 +#: compensation/tables.py:33 compensation/tables.py:204 ema/tables.py:39 +#: intervention/tables.py:33 konova/filters/mixins.py:98 msgid "Parcel gmrkng" msgstr "Gemarkung" -#: compensation/tables.py:52 compensation/tables.py:226 ema/tables.py:50 -#: intervention/tables.py:51 +#: compensation/tables.py:50 compensation/tables.py:225 ema/tables.py:50 +#: intervention/tables.py:50 msgid "Editable" msgstr "Freigegeben" -#: compensation/tables.py:58 compensation/tables.py:232 ema/tables.py:56 -#: intervention/tables.py:57 +#: compensation/tables.py:56 compensation/tables.py:231 ema/tables.py:56 +#: intervention/tables.py:56 msgid "Last edit" msgstr "Zuletzt bearbeitet" -#: compensation/tables.py:89 compensation/tables.py:264 ema/tables.py:89 -#: intervention/tables.py:88 +#: compensation/tables.py:87 compensation/tables.py:263 ema/tables.py:89 +#: intervention/tables.py:87 msgid "Open {}" msgstr "Öffne {}" -#: compensation/tables.py:114 intervention/tables.py:111 -msgid "Not checked yet" -msgstr "Noch nicht geprüft" - -#: compensation/tables.py:119 intervention/tables.py:116 -msgid "Checked on {} by {}" -msgstr "Am {} von {} geprüft worden" - -#: compensation/tables.py:160 -#: compensation/templates/compensation/detail/compensation/view.html:81 +#: compensation/tables.py:163 +#: compensation/templates/compensation/detail/compensation/view.html:96 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:58 #: compensation/templates/compensation/detail/eco_account/view.html:48 -#: ema/tables.py:131 ema/templates/ema/detail/view.html:38 -#: intervention/tables.py:157 -#: intervention/templates/intervention/detail/view.html:85 +#: ema/tables.py:130 ema/templates/ema/detail/view.html:38 +#: intervention/tables.py:161 +#: intervention/templates/intervention/detail/view.html:90 msgid "Not recorded yet" msgstr "Noch nicht verzeichnet" -#: compensation/tables.py:165 compensation/tables.py:324 ema/tables.py:136 -#: intervention/tables.py:162 +#: compensation/tables.py:166 compensation/tables.py:321 ema/tables.py:133 +#: intervention/tables.py:164 msgid "Recorded on {} by {}" msgstr "Am {} von {} verzeichnet worden" -#: compensation/tables.py:187 compensation/tables.py:346 ema/tables.py:157 -#: intervention/tables.py:183 +#: compensation/tables.py:186 compensation/tables.py:343 ema/tables.py:154 +#: intervention/tables.py:185 msgid "Full access granted" msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden" -#: compensation/tables.py:187 compensation/tables.py:346 ema/tables.py:157 -#: intervention/tables.py:183 +#: compensation/tables.py:186 compensation/tables.py:343 ema/tables.py:154 +#: intervention/tables.py:185 msgid "Access not granted" msgstr "Nicht freigegeben - Datensatz nur lesbar" -#: compensation/tables.py:210 +#: compensation/tables.py:209 #: compensation/templates/compensation/detail/eco_account/view.html:36 #: konova/templates/konova/widgets/progressbar.html:3 msgid "Available" msgstr "Verfügbar" -#: compensation/tables.py:241 +#: compensation/tables.py:240 msgid "Eco Accounts" msgstr "Ökokonten" -#: compensation/tables.py:319 +#: compensation/tables.py:318 msgid "Not recorded yet. Can not be used for deductions, yet." msgstr "" "Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden." @@ -790,7 +795,7 @@ msgstr "Menge" #: intervention/templates/intervention/detail/includes/documents.html:39 #: intervention/templates/intervention/detail/includes/payments.html:39 #: intervention/templates/intervention/detail/includes/revocation.html:43 -#: templates/log.html:10 user/templates/user/team/index.html:32 +#: templates/log.html:10 user/templates/user/team/index.html:33 msgid "Action" msgstr "Aktionen" @@ -871,7 +876,7 @@ msgstr "Dokumente" #: compensation/templates/compensation/detail/eco_account/includes/documents.html:14 #: ema/templates/ema/detail/includes/documents.html:14 #: intervention/templates/intervention/detail/includes/documents.html:14 -#: konova/forms.py:445 +#: konova/forms.py:491 msgid "Add new document" msgstr "Neues Dokument hinzufügen" @@ -879,7 +884,7 @@ msgstr "Neues Dokument hinzufügen" #: compensation/templates/compensation/detail/eco_account/includes/documents.html:31 #: ema/templates/ema/detail/includes/documents.html:31 #: intervention/templates/intervention/detail/includes/documents.html:31 -#: konova/forms.py:402 +#: konova/forms.py:448 msgid "Created on" msgstr "Erstellt" @@ -887,7 +892,7 @@ msgstr "Erstellt" #: compensation/templates/compensation/detail/eco_account/includes/documents.html:61 #: ema/templates/ema/detail/includes/documents.html:61 #: intervention/templates/intervention/detail/includes/documents.html:65 -#: konova/forms.py:507 +#: konova/forms.py:553 msgid "Edit document" msgstr "Dokument bearbeiten" @@ -963,63 +968,69 @@ msgstr "Neuen Ausgangszustand hinzufügen" msgid "Missing surfaces according to states after: " msgstr "Fehlende Flächenmengen laut Zielzustand: " -#: compensation/templates/compensation/detail/compensation/view.html:44 -msgid "Is CEF compensation" -msgstr "Ist CEF Maßnahme" - #: compensation/templates/compensation/detail/compensation/view.html:47 #: compensation/templates/compensation/detail/compensation/view.html:57 +#: compensation/templates/compensation/detail/compensation/view.html:67 +#: compensation/templates/compensation/detail/eco_account/view.html:78 +#: ema/templates/ema/detail/view.html:64 #: venv/lib/python3.7/site-packages/django/forms/widgets.py:710 msgid "Yes" msgstr "Ja" #: compensation/templates/compensation/detail/compensation/view.html:49 #: compensation/templates/compensation/detail/compensation/view.html:59 +#: compensation/templates/compensation/detail/compensation/view.html:69 +#: compensation/templates/compensation/detail/eco_account/view.html:80 +#: ema/templates/ema/detail/view.html:66 #: venv/lib/python3.7/site-packages/django/forms/widgets.py:711 msgid "No" msgstr "Nein" #: compensation/templates/compensation/detail/compensation/view.html:54 +msgid "Is CEF compensation" +msgstr "Ist CEF Maßnahme" + +#: compensation/templates/compensation/detail/compensation/view.html:64 msgid "Is Coherence keeping compensation" msgstr "Ist Kohärenzsicherungsmaßnahme" -#: compensation/templates/compensation/detail/compensation/view.html:71 -#: intervention/templates/intervention/detail/view.html:75 +#: compensation/templates/compensation/detail/compensation/view.html:86 +#: intervention/templates/intervention/detail/view.html:80 msgid "Checked on " msgstr "Geprüft am " -#: compensation/templates/compensation/detail/compensation/view.html:71 -#: compensation/templates/compensation/detail/compensation/view.html:85 +#: compensation/templates/compensation/detail/compensation/view.html:86 +#: compensation/templates/compensation/detail/compensation/view.html:100 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:56 #: compensation/templates/compensation/detail/eco_account/view.html:52 #: ema/templates/ema/detail/view.html:42 -#: intervention/templates/intervention/detail/view.html:75 -#: intervention/templates/intervention/detail/view.html:89 +#: intervention/templates/intervention/detail/view.html:80 +#: intervention/templates/intervention/detail/view.html:94 msgid "by" msgstr "von" -#: compensation/templates/compensation/detail/compensation/view.html:85 +#: compensation/templates/compensation/detail/compensation/view.html:100 #: compensation/templates/compensation/detail/eco_account/view.html:52 #: ema/templates/ema/detail/view.html:42 -#: intervention/templates/intervention/detail/view.html:89 +#: intervention/templates/intervention/detail/view.html:94 msgid "Recorded on " msgstr "Verzeichnet am" -#: compensation/templates/compensation/detail/compensation/view.html:92 -#: compensation/templates/compensation/detail/eco_account/view.html:75 +#: compensation/templates/compensation/detail/compensation/view.html:107 +#: compensation/templates/compensation/detail/eco_account/view.html:85 #: compensation/templates/compensation/report/compensation/report.html:24 #: compensation/templates/compensation/report/eco_account/report.html:37 -#: ema/templates/ema/detail/view.html:61 +#: ema/templates/ema/detail/view.html:71 #: ema/templates/ema/report/report.html:24 -#: intervention/templates/intervention/detail/view.html:108 +#: intervention/templates/intervention/detail/view.html:113 #: intervention/templates/intervention/report/report.html:87 msgid "Last modified" msgstr "Zuletzt bearbeitet" -#: compensation/templates/compensation/detail/compensation/view.html:106 -#: compensation/templates/compensation/detail/eco_account/view.html:89 -#: ema/templates/ema/detail/view.html:75 -#: intervention/templates/intervention/detail/view.html:122 +#: compensation/templates/compensation/detail/compensation/view.html:121 +#: compensation/templates/compensation/detail/eco_account/view.html:99 +#: ema/templates/ema/detail/view.html:85 +#: intervention/templates/intervention/detail/view.html:127 msgid "Shared with" msgstr "Freigegeben für" @@ -1058,7 +1069,7 @@ msgstr "Eingriffskennung" #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:37 #: intervention/templates/intervention/detail/includes/deductions.html:34 -#: user/models/user_action.py:23 +#: user/models/user_action.py:24 msgid "Created" msgstr "Erstellt" @@ -1095,8 +1106,8 @@ msgstr "Keine Flächenmenge für Abbuchungen eingegeben. Bitte bearbeiten." #: intervention/templates/intervention/detail/view.html:55 #: intervention/templates/intervention/detail/view.html:59 #: intervention/templates/intervention/detail/view.html:63 -#: intervention/templates/intervention/detail/view.html:95 -#: intervention/templates/intervention/detail/view.html:99 +#: intervention/templates/intervention/detail/view.html:100 +#: intervention/templates/intervention/detail/view.html:104 msgid "Missing" msgstr "fehlt" @@ -1150,17 +1161,17 @@ msgid "Compensation {} edited" msgstr "Kompensation {} bearbeitet" #: compensation/views/compensation.py:182 compensation/views/eco_account.py:173 -#: ema/views.py:240 intervention/views.py:335 +#: ema/views.py:240 intervention/views.py:338 msgid "Edit {}" msgstr "Bearbeite {}" -#: compensation/views/compensation.py:261 compensation/views/eco_account.py:359 -#: ema/views.py:194 intervention/views.py:539 +#: compensation/views/compensation.py:268 compensation/views/eco_account.py:359 +#: ema/views.py:194 intervention/views.py:542 msgid "Log" msgstr "Log" -#: compensation/views/compensation.py:605 compensation/views/eco_account.py:727 -#: ema/views.py:558 intervention/views.py:685 +#: compensation/views/compensation.py:612 compensation/views/eco_account.py:727 +#: ema/views.py:558 intervention/views.py:688 msgid "Report {}" msgstr "Bericht {}" @@ -1181,40 +1192,40 @@ msgid "Eco-account removed" msgstr "Ökokonto entfernt" #: compensation/views/eco_account.py:380 ema/views.py:282 -#: intervention/views.py:638 +#: intervention/views.py:641 msgid "{} unrecorded" msgstr "{} entzeichnet" #: compensation/views/eco_account.py:380 ema/views.py:282 -#: intervention/views.py:638 +#: intervention/views.py:641 msgid "{} recorded" msgstr "{} verzeichnet" #: compensation/views/eco_account.py:804 ema/views.py:628 -#: intervention/views.py:436 +#: intervention/views.py:439 msgid "{} has already been shared with you" msgstr "{} wurde bereits für Sie freigegeben" #: compensation/views/eco_account.py:809 ema/views.py:633 -#: intervention/views.py:441 +#: intervention/views.py:444 msgid "{} has been shared with you" msgstr "{} ist nun für Sie freigegeben" #: compensation/views/eco_account.py:816 ema/views.py:640 -#: intervention/views.py:448 +#: intervention/views.py:451 msgid "Share link invalid" msgstr "Freigabelink ungültig" #: compensation/views/eco_account.py:839 ema/views.py:663 -#: intervention/views.py:471 +#: intervention/views.py:474 msgid "Share settings updated" msgstr "Freigabe Einstellungen aktualisiert" -#: ema/forms.py:41 ema/views.py:98 +#: ema/forms.py:43 ema/views.py:98 msgid "New EMA" msgstr "Neue EMA hinzufügen" -#: ema/forms.py:102 +#: ema/forms.py:106 msgid "Edit EMA" msgstr "Bearbeite EMA" @@ -1300,23 +1311,23 @@ msgid "Intervention handler detail" msgstr "Detailangabe zum Eingriffsverursacher" #: intervention/forms/forms.py:173 -#: intervention/templates/intervention/detail/view.html:96 +#: intervention/templates/intervention/detail/view.html:101 #: intervention/templates/intervention/report/report.html:79 #: intervention/utils/quality.py:73 msgid "Registration date" msgstr "Datum Zulassung bzw. Satzungsbeschluss" #: intervention/forms/forms.py:185 -#: intervention/templates/intervention/detail/view.html:100 +#: intervention/templates/intervention/detail/view.html:105 #: intervention/templates/intervention/report/report.html:83 msgid "Binding on" -msgstr "Datum Bestandskraft" +msgstr "Datum Bestandskraft bzw. Rechtskraft" #: intervention/forms/forms.py:211 intervention/views.py:95 msgid "New intervention" msgstr "Neuer Eingriff" -#: intervention/forms/forms.py:294 +#: intervention/forms/forms.py:298 msgid "Edit intervention" msgstr "Eingriff bearbeiten" @@ -1392,7 +1403,7 @@ msgstr "Kompensationen und Zahlungen geprüft" msgid "Run check" msgstr "Prüfung vornehmen" -#: intervention/forms/modalForms.py:264 konova/forms.py:548 +#: intervention/forms/modalForms.py:264 konova/forms.py:594 msgid "" "I, {} {}, confirm that all necessary control steps have been performed by " "myself." @@ -1479,7 +1490,7 @@ msgid "Remove payment" msgstr "Zahlung entfernen" #: intervention/templates/intervention/detail/includes/revocation.html:8 -#: intervention/templates/intervention/detail/view.html:104 +#: intervention/templates/intervention/detail/view.html:109 msgid "Revocations" msgstr "Widersprüche" @@ -1501,7 +1512,7 @@ msgstr "Widerspruch entfernen" msgid "Intervention handler" msgstr "Eingriffsverursacher" -#: intervention/templates/intervention/detail/view.html:103 +#: intervention/templates/intervention/detail/view.html:108 msgid "Exists" msgstr "vorhanden" @@ -1520,7 +1531,7 @@ msgstr "Widersprüche liegen vor" #: intervention/utils/quality.py:76 msgid "Binding date" -msgstr "Datum Bestandskraft" +msgstr "Datum Bestandskraft bzw. Rechtskraft" #: intervention/utils/quality.py:79 msgid "Laws" @@ -1540,19 +1551,19 @@ msgstr "Eingriffe - Übersicht" msgid "Intervention {} added" msgstr "Eingriff {} hinzugefügt" -#: intervention/views.py:323 +#: intervention/views.py:326 msgid "Intervention {} edited" msgstr "Eingriff {} bearbeitet" -#: intervention/views.py:359 +#: intervention/views.py:362 msgid "{} removed" msgstr "{} entfernt" -#: intervention/views.py:492 +#: intervention/views.py:495 msgid "Check performed" msgstr "Prüfung durchgeführt" -#: intervention/views.py:643 +#: intervention/views.py:646 msgid "There are errors on this intervention:" msgstr "Es liegen Fehler in diesem Eingriff vor:" @@ -1582,7 +1593,7 @@ msgid "Search for file number" msgstr "Nach Aktenzeichen suchen" #: konova/filters/mixins.py:85 -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:13 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:18 msgid "District" msgstr "Kreis" @@ -1595,7 +1606,7 @@ msgid "Search for parcel gmrkng" msgstr "Nach Gemarkung suchen" #: konova/filters/mixins.py:111 -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:34 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:39 msgid "Parcel" msgstr "Flur" @@ -1604,7 +1615,7 @@ msgid "Search for parcel" msgstr "Nach Flur suchen" #: konova/filters/mixins.py:124 -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:35 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:40 msgid "Parcel counter" msgstr "Flurstückzähler" @@ -1613,7 +1624,7 @@ msgid "Search for parcel counter" msgstr "Nach Flurstückzähler suchen" #: konova/filters/mixins.py:138 -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:36 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:41 msgid "Parcel number" msgstr "Flurstücknenner" @@ -1637,69 +1648,74 @@ msgstr "Nach Zulassungsbehörde suchen" msgid "Search for conservation office" msgstr "Nch Eintragungsstelle suchen" -#: konova/forms.py:39 templates/form/collapsable/form.html:62 +#: konova/forms.py:41 templates/form/collapsable/form.html:62 msgid "Save" msgstr "Speichern" -#: konova/forms.py:73 +#: konova/forms.py:75 msgid "Not editable" msgstr "Nicht editierbar" -#: konova/forms.py:176 konova/forms.py:348 +#: konova/forms.py:178 konova/forms.py:394 msgid "Confirm" msgstr "Bestätige" -#: konova/forms.py:188 konova/forms.py:357 +#: konova/forms.py:190 konova/forms.py:403 msgid "Remove" msgstr "Löschen" -#: konova/forms.py:190 +#: konova/forms.py:192 msgid "You are about to remove {} {}" msgstr "Sie sind dabei {} {} zu löschen" -#: konova/forms.py:277 konova/utils/quality.py:44 konova/utils/quality.py:46 +#: konova/forms.py:280 konova/utils/quality.py:44 konova/utils/quality.py:46 #: templates/form/collapsable/form.html:45 msgid "Geometry" msgstr "Geometrie" -#: konova/forms.py:358 +#: konova/forms.py:331 +msgid "Only surfaces allowed. Points or lines must be buffered." +msgstr "" +"Nur Flächen erlaubt. Punkte oder Linien müssen zu Flächen gepuffert werden." + +#: konova/forms.py:404 msgid "Are you sure?" msgstr "Sind Sie sicher?" -#: konova/forms.py:404 +#: konova/forms.py:450 msgid "When has this file been created? Important for photos." msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?" -#: konova/forms.py:415 +#: konova/forms.py:461 #: venv/lib/python3.7/site-packages/django/db/models/fields/files.py:231 msgid "File" msgstr "Datei" -#: konova/forms.py:417 +#: konova/forms.py:463 msgid "Allowed formats: pdf, jpg, png. Max size 15 MB." msgstr "Formate: pdf, jpg, png. Maximal 15 MB." -#: konova/forms.py:482 +#: konova/forms.py:528 msgid "Added document" msgstr "Dokument hinzugefügt" -#: konova/forms.py:539 +#: konova/forms.py:585 msgid "Confirm record" msgstr "Verzeichnen bestätigen" -#: konova/forms.py:547 +#: konova/forms.py:593 msgid "Record data" msgstr "Daten verzeichnen" -#: konova/forms.py:554 +#: konova/forms.py:600 msgid "Confirm unrecord" msgstr "Entzeichnen bestätigen" -#: konova/forms.py:555 +#: konova/forms.py:601 msgid "Unrecord data" msgstr "Daten entzeichnen" -#: konova/forms.py:556 +#: konova/forms.py:602 msgid "I, {} {}, confirm that this data must be unrecorded." msgstr "" "Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen." @@ -1748,10 +1764,6 @@ msgstr "" msgid "English" msgstr "" -#: konova/templates/konova/includes/parcels/parcel_table_content.html:18 -msgid "Show more..." -msgstr "Mehr anzeigen..." - #: konova/templates/konova/includes/parcels/parcel_table_frame.html:5 msgid "Parcels can not be calculated, since no geometry is given." msgstr "" @@ -1759,22 +1771,26 @@ msgstr "" "wurde." #: konova/templates/konova/includes/parcels/parcel_table_frame.html:11 +msgid "Parcels found" +msgstr "Flurstücke" + +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:16 msgid "Municipal" msgstr "Gemeinde" -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:12 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:17 msgid "Municipal key" msgstr "Gemeindeschlüssel" -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:14 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:19 msgid "District key" msgstr "Kreisschlüssel" -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:32 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:37 msgid "Parcel group" msgstr "Gemarkung" -#: konova/templates/konova/includes/parcels/parcel_table_frame.html:33 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:38 msgid "Parcel group key" msgstr "Gemarkungsschlüssel" @@ -1808,11 +1824,6 @@ msgstr "Im Browser öffnen" msgid "View in LANIS" msgstr "In LANIS öffnen" -#: konova/templates/konova/widgets/checkbox-tree-select.html:4 -#: templates/generic_index.html:56 -msgid "Search" -msgstr "Suchen" - #: konova/templates/konova/widgets/generate-content-input.html:6 msgid "Generate new" msgstr "Neu generieren" @@ -1825,6 +1836,12 @@ msgstr "In Zwischenablage kopieren" msgid "Copied to clipboard" msgstr "In Zwischenablage kopiert" +#: konova/templates/konova/widgets/tree/checkbox/checkbox-tree-select.html:4 +#: konova/templates/konova/widgets/tree/radio/radio-tree-select.html:4 +#: templates/generic_index.html:56 +msgid "Search" +msgstr "Suchen" + #: konova/utils/mailer.py:68 konova/utils/mailer.py:137 msgid "{} - Shared access removed" msgstr "{} - Zugriff entzogen" @@ -2054,6 +2071,19 @@ msgstr "Geometriekonflikt mit folgenden Einträgen erkannt: {}" msgid "This intervention has {} revocations" msgstr "Dem Eingriff liegen {} Widersprüche vor" +#: konova/utils/message_templates.py:86 +msgid "Checked on {} by {}" +msgstr "Am {} von {} geprüft worden" + +#: konova/utils/message_templates.py:87 +msgid "Data has changed since last check on {} by {}" +msgstr "" +"Daten wurden nach der letzten Prüfung geändert. Letzte Prüfung am {} durch {}" + +#: konova/utils/message_templates.py:88 +msgid "Current data not checked yet" +msgstr "Momentane Daten noch nicht geprüft" + #: konova/utils/messenger.py:70 msgid "{} checked" msgstr "{} geprüft" @@ -2070,7 +2100,7 @@ msgstr "{} wurde erfolgreich vom Nutzer {} geprüft! {}" msgid "missing" msgstr "fehlt" -#: konova/views.py:96 templates/navbars/navbar.html:16 +#: konova/views.py:99 templates/navbars/navbar.html:16 msgid "Home" msgstr "Home" @@ -2484,8 +2514,9 @@ msgid "" msgstr "" "\n" " Diese Daten sind noch nicht veröffentlicht und/oder haben das " -"Bestandskraftdatum noch nicht erreicht. Sie können daher aktuell nicht " -"eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt wieder vorbei. \n" +"Bestands-/Rechtskraftdatum noch nicht erreicht. Sie können daher aktuell " +"nicht eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt wieder " +"vorbei. \n" " " #: templates/table/gmrkng_col.html:6 @@ -2536,11 +2567,11 @@ msgstr "Neuen Token generieren" msgid "A new token needs to be validated by an administrator!" msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!" -#: user/forms.py:168 user/forms.py:172 user/forms.py:332 user/forms.py:337 +#: user/forms.py:168 user/forms.py:172 user/forms.py:354 user/forms.py:359 msgid "Team name" msgstr "Team Name" -#: user/forms.py:179 user/forms.py:345 user/templates/user/team/index.html:30 +#: user/forms.py:179 user/forms.py:367 user/templates/user/team/index.html:30 msgid "Description" msgstr "Beschreibung" @@ -2568,43 +2599,63 @@ msgstr "" "Sie werden standardmäßig der Administrator dieses Teams. Sie müssen sich " "selbst nicht zur Liste der Mitglieder hinzufügen." -#: user/forms.py:218 user/forms.py:279 +#: user/forms.py:218 user/forms.py:296 msgid "Name already taken. Try another." msgstr "Name bereits vergeben. Probieren Sie einen anderen." -#: user/forms.py:249 -msgid "Admin" -msgstr "Administrator" +#: user/forms.py:248 +msgid "Admins" +msgstr "Administratoren" #: user/forms.py:250 msgid "Administrators manage team details and members" msgstr "Administratoren verwalten die Teamdaten und Mitglieder" -#: user/forms.py:263 -msgid "Selected admin ({}) needs to be a member of this team." -msgstr "Gewählter Administrator ({}) muss ein Mitglied des Teams sein." +#: user/forms.py:273 +msgid "Selected admins need to be members of this team." +msgstr "Gewählte Administratoren müssen Teammitglieder sein." -#: user/forms.py:291 user/templates/user/team/index.html:54 +#: user/forms.py:280 +msgid "There must be at least one admin on this team." +msgstr "Es muss mindestens einen Administrator für das Team geben." + +#: user/forms.py:308 user/templates/user/team/index.html:60 msgid "Edit team" msgstr "Team bearbeiten" -#: user/forms.py:323 user/templates/user/team/index.html:50 +#: user/forms.py:335 +msgid "" +"ATTENTION!\n" +"\n" +"Removing the team means all members will lose their access to data, based on " +"this team! \n" +"\n" +"Are you sure to remove this team?" +msgstr "" +"ACHTUNG!\n" +"\n" +"Wenn dieses Team gelöscht wird, verlieren alle Teammitglieder den Zugriff " +"auf die Daten, die nur über dieses Team freigegeben sind!\n" +"\n" +"Sind Sie sicher, dass Sie dieses Team löschen möchten?" + +#: user/forms.py:345 user/templates/user/team/index.html:56 msgid "Leave team" msgstr "Team verlassen" -#: user/forms.py:356 +#: user/forms.py:378 msgid "Team" msgstr "Team" -#: user/models/user_action.py:22 +#: user/models/user_action.py:23 msgid "Unrecorded" msgstr "Entzeichnet" -#: user/models/user_action.py:24 +#: user/models/user_action.py:25 msgid "Edited" msgstr "Bearbeitet" -#: user/models/user_action.py:25 +#: user/models/user_action.py:26 msgid "Deleted" msgstr "Gelöscht" @@ -2621,8 +2672,8 @@ msgid "Name" msgstr "" #: user/templates/user/index.html:21 -msgid "Groups" -msgstr "Gruppen" +msgid "Permissions" +msgstr "Berechtigungen" #: user/templates/user/index.html:34 msgid "" @@ -2678,7 +2729,11 @@ msgstr "Neues Team hinzufügen" msgid "Members" msgstr "Mitglieder" -#: user/templates/user/team/index.html:57 +#: user/templates/user/team/index.html:32 +msgid "Administrator" +msgstr "" + +#: user/templates/user/team/index.html:63 msgid "Remove team" msgstr "Team entfernen" @@ -2730,19 +2785,19 @@ msgstr "API Nutzer Token" msgid "New team added" msgstr "Neues Team hinzugefügt" -#: user/views.py:191 +#: user/views.py:192 msgid "Team edited" msgstr "Team bearbeitet" -#: user/views.py:204 +#: user/views.py:206 msgid "Team removed" msgstr "Team gelöscht" -#: user/views.py:218 +#: user/views.py:220 msgid "You are not a member of this team" msgstr "Sie sind kein Mitglied dieses Teams" -#: user/views.py:225 +#: user/views.py:227 msgid "Left Team" msgstr "Team verlassen" @@ -4245,6 +4300,12 @@ msgstr "" msgid "Unable to connect to qpid with SASL mechanism %s" msgstr "" +#~ msgid "Groups" +#~ msgstr "Gruppen" + +#~ msgid "Show more..." +#~ msgstr "Mehr anzeigen..." + #~ msgid "Kreis" #~ msgstr "Kreis" diff --git a/templates/form/table/generic_table_form.html b/templates/form/table/generic_table_form.html index a89ee4bf..5c00b89a 100644 --- a/templates/form/table/generic_table_form.html +++ b/templates/form/table/generic_table_form.html @@ -11,7 +11,7 @@ {% if form.form_caption is not None %} - {{ form.form_caption }} + {{ form.form_caption|linebreaks }} {% endif %}
diff --git a/templates/map/client/assets/logo.png b/templates/map/client/assets/logo.png new file mode 100644 index 00000000..aca5d823 Binary files /dev/null and b/templates/map/client/assets/logo.png differ diff --git a/templates/map/client/config.json b/templates/map/client/config.json new file mode 100644 index 00000000..1177cf15 --- /dev/null +++ b/templates/map/client/config.json @@ -0,0 +1,139 @@ +{ + "layers": + [ + { "folder": 5, "type": "WMS", "title": "KOM Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_f&", "name": "kom_f" }, + { "folder": 5, "type": "WMS", "title": "KOM Linien", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_l&", "name": "kom_l" }, + { "folder": 5, "type": "WMS", "title": "KOM Punkte", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=komon&", "name": "kom_p" }, + + { "folder": 6, "type": "WMS", "title": "EIV Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_f&", "name": "eiv_f" }, + { "folder": 6, "type": "WMS", "title": "EIV Linien", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_l&", "name": "eiv_l" }, + { "folder": 6, "type": "WMS", "title": "EIV Punkte", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_p&", "name": "eiv_p" }, + + { "folder": 7, "type": "WMS", "title": "OEK Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=oek_f&", "name": "oek_f" }, + + { "folder": 8, "type": "WMS", "title": "EMA Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ema_f&", "name": "ema_f" }, + + { "folder": 9, "type": "WMS", "title": "MAE Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=mae&", "name": "mae" }, + + { "folder": 10, "type": "WMS", "title": "Naturschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=naturschutzgebiet&", "name": "naturschutzgebiet" }, + { "folder": 10, "type": "WMS", "title": "Naturparkzonen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=naturparkzonen&", "name": "naturparkzonen" }, + { "folder": 10, "type": "WMS", "title": "Landschaftsschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=landschaftsschutzgebiet&", "name": "landschaftsschutzgebiet" }, + { "folder": 10, "type": "WMS", "title": "Vogelschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=vogelschutzgebiet&", "name": "vogelschutzgebiet" }, + { "folder": 10, "type": "WMS", "title": "FFH Gebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ffh&", "name": "ffh" }, + + { "folder": 11, "type": "WMS", "title": "Nationalpark Zonen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=nationalpark_zonen&", "name": "nationalpark_zonen" }, + { "folder": 11, "type": "WMS", "title": "Nationalpark Grenzen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=nationalpark_grenze&", "name": "nationalpark_grenze" }, + + { "folder": 12, "type": "WMS", "title": "Naturräume Grenzen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=natraum_lkompvo_grenzen&", "name": "natraum_lkompvo_grenzen" }, + { "folder": 12, "type": "WMS", "title": "Naturräume Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=natraum_lkompvo&", "name": "natraum_lkompvo" }, + + { "folder": 1, "type": "WMS", "title": "Lagebezeichnungen", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Lagebezeichnungen" }, + { "folder": 1, "type": "WMS", "title": "Flurstücke", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Flurstueck", "active": true}, + { "folder": 1, "type": "WMS", "title": "Gebäude / Bauwerke", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "GebaeudeBauwerke" }, + { "folder": 1, "type": "WMS", "title": "Nutzung", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Nutzung" }, + + { "folder": 2, "type": "WMS", "title": "Landkreise", "url": "http://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Landkreise" }, + { "folder": 2, "type": "WMS", "title": "Verbandsgemeinden", "url": "http://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Verbandsgemeinden" }, + { "folder": 2, "type": "WMS", "title": "Gemeinden", "url": "http://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Gemeinden" }, + + { "folder": 0, "type": "WMS", "title": "Webatlas farbig", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_WebAtlasRP/MapServer/WmsServer?", "name": "RP_WebAtlasRP", "active": true }, + { "folder": 0, "type": "WMS", "title": "Webatlas grau", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_ETRS_Gt/MapServer/WmsServer?", "name": "0", "active": false }, + { "folder": 0, "type": "WMS", "title": "Luftbilder", "attribution": "LVermGeo", "url": "http://geo4.service24.rlp.de/wms/dop_basis.fcgi?", "name": "rp_dop", "active": false }, + { "folder": 0, "type": "WMS", "title": "TopPlusOpen", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_topplus_open?", "name": "web", "active": false }, + { "folder": 0, "type": "OSM", "title": "Open Street Map", "attribution": "OSM", "active": false } + ], + + "folders": + [ + { "title": "Hintergrund", "parent": -1 }, + { "title": "ALKIS Liegenschaften", "parent": -1 }, + { "title": "Verwaltungsgrenzen", "parent": -1 }, + { "title": "Geofachdaten", "parent": -1 }, + { "title": "Kompensationsverzeichnis", "parent": 3 }, + { "title": "Kompensationen", "parent": 4 }, + { "title": "Eingriffe", "parent": 4 }, + { "title": "Ökokonten", "parent": 4 }, + { "title": "EMA", "parent": 4 }, + { "title": "MAE", "parent": 4 }, + { "title": "Schutzgebiete", "parent": 3 }, + { "title": "Nationalparke", "parent": 10 }, + { "title": "Naturräume", "parent": 10 } + ], + + "projections": + [ + [ "EPSG:25832", "+proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs" ] + ], + + "map": + { + "projection": "EPSG:25832", + "center": [ 385000, 5543000 ], + "minZoom": 5, + "maxZoom": 22, + "zoom": 9, + "attribution": "LANIS RLP" + }, + + "output": + { + "id": "netgis-storage" + }, + + "search": + { + "url": "/client/proxy?https://www.geoportal.rlp.de/mapbender/geoportal/gaz_geom_mobile.php?outputFormat=json&resultTarget=web&searchEPSG={epsg}&maxResults=5&maxRows=5&featureClass=P&style=full&searchText={q}&name_startsWith={q}" + }, + + "export": + { + "logo": "/static/assets/logo.png", + "gifWebWorker": "/static/libs/gifjs/0.2.0/gif.worker.js", + "defaultFilename": "Export", + "defaultMargin": 10 + }, + + "tools": + { + "buffer": + { + "defaultRadius": 2, + "defaultSegments": 2 + } + }, + + "styles": + { + "editLayer": + { + "fill": "rgba( 255, 0, 0, 0.2 )", + "stroke": "#ff0000", + "strokeWidth": 3, + "pointRadius": 6 + }, + + "select": + { + "fill": "rgba( 0, 127, 255, 0.5 )", + "stroke": "#007fff", + "strokeWidth": 3, + "pointRadius": 6 + }, + + "sketch": + { + "fill": "rgba( 0, 127, 255, 0.2 )", + "stroke": "#0080ff", + "strokeWidth": 3, + "pointRadius": 6 + }, + + "modify": + { + "fill": "rgba( 0, 127, 255, 0.5 )", + "stroke": "#0080ff", + "strokeWidth": 3, + "pointRadius": 6 + } + } +} \ No newline at end of file diff --git a/templates/map/client/index.html b/templates/map/client/index.html new file mode 100644 index 00000000..4612cd25 --- /dev/null +++ b/templates/map/client/index.html @@ -0,0 +1,33 @@ +{% load static %} + + + + + + + +
+
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/LICENSE.txt b/templates/map/client/libs/fontawesome/5.12.0/LICENSE.txt new file mode 100644 index 00000000..f31bef92 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/LICENSE.txt @@ -0,0 +1,34 @@ +Font Awesome Free License +------------------------- + +Font Awesome Free is free, open source, and GPL friendly. You can use it for +commercial projects, open source projects, or really almost whatever you want. +Full Font Awesome Free license: https://fontawesome.com/license/free. + +# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) +In the Font Awesome Free download, the CC BY 4.0 license applies to all icons +packaged as SVG and JS file types. + +# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) +In the Font Awesome Free download, the SIL OFL license applies to all icons +packaged as web and desktop font files. + +# Code: MIT License (https://opensource.org/licenses/MIT) +In the Font Awesome Free download, the MIT license applies to all non-font and +non-icon files. + +# Attribution +Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font +Awesome Free files already contain embedded comments with sufficient +attribution, so you shouldn't need to do anything additional when using these +files normally. + +We've kept attribution comments terse, so we ask that you do not actively work +to remove them from files, especially code. They're a great way for folks to +learn about Font Awesome. + +# Brand Icons +All brand icons are trademarks of their respective owners. The use of these +trademarks does not indicate endorsement of the trademark holder by Font +Awesome, nor vice versa. **Please do not use brand logos for any purpose except +to represent the company, product, or service to which they refer.** diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/all.css b/templates/map/client/libs/fontawesome/5.12.0/css/all.css new file mode 100644 index 00000000..06c11a9a --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/all.css @@ -0,0 +1,4450 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa, +.fas, +.far, +.fal, +.fad, +.fab { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; } + +.fa-lg { + font-size: 1.33333em; + line-height: 0.75em; + vertical-align: -.0667em; } + +.fa-xs { + font-size: .75em; } + +.fa-sm { + font-size: .875em; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: 2.5em; + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: -2em; + position: absolute; + text-align: center; + width: 2em; + line-height: inherit; } + +.fa-border { + border: solid 0.08em #eee; + border-radius: .1em; + padding: .2em .25em .15em; } + +.fa-pull-left { + float: left; } + +.fa-pull-right { + float: right; } + +.fa.fa-pull-left, +.fas.fa-pull-left, +.far.fa-pull-left, +.fal.fa-pull-left, +.fab.fa-pull-left { + margin-right: .3em; } + +.fa.fa-pull-right, +.fas.fa-pull-right, +.far.fa-pull-right, +.fal.fa-pull-right, +.fab.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(360deg); + transform: rotate(360deg); } } + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); } + +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-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); + transform: scale(1, -1); } + +.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-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, +:root .fa-flip-both { + -webkit-filter: none; + filter: none; } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: #fff; } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ +.fa-500px:before { + content: "\f26e"; } + +.fa-accessible-icon:before { + content: "\f368"; } + +.fa-accusoft:before { + content: "\f369"; } + +.fa-acquisitions-incorporated:before { + content: "\f6af"; } + +.fa-ad:before { + content: "\f641"; } + +.fa-address-book:before { + content: "\f2b9"; } + +.fa-address-card:before { + content: "\f2bb"; } + +.fa-adjust:before { + content: "\f042"; } + +.fa-adn:before { + content: "\f170"; } + +.fa-adobe:before { + content: "\f778"; } + +.fa-adversal:before { + content: "\f36a"; } + +.fa-affiliatetheme:before { + content: "\f36b"; } + +.fa-air-freshener:before { + content: "\f5d0"; } + +.fa-airbnb:before { + content: "\f834"; } + +.fa-algolia:before { + content: "\f36c"; } + +.fa-align-center:before { + content: "\f037"; } + +.fa-align-justify:before { + content: "\f039"; } + +.fa-align-left:before { + content: "\f036"; } + +.fa-align-right:before { + content: "\f038"; } + +.fa-alipay:before { + content: "\f642"; } + +.fa-allergies:before { + content: "\f461"; } + +.fa-amazon:before { + content: "\f270"; } + +.fa-amazon-pay:before { + content: "\f42c"; } + +.fa-ambulance:before { + content: "\f0f9"; } + +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; } + +.fa-amilia:before { + content: "\f36d"; } + +.fa-anchor:before { + content: "\f13d"; } + +.fa-android:before { + content: "\f17b"; } + +.fa-angellist:before { + content: "\f209"; } + +.fa-angle-double-down:before { + content: "\f103"; } + +.fa-angle-double-left:before { + content: "\f100"; } + +.fa-angle-double-right:before { + content: "\f101"; } + +.fa-angle-double-up:before { + content: "\f102"; } + +.fa-angle-down:before { + content: "\f107"; } + +.fa-angle-left:before { + content: "\f104"; } + +.fa-angle-right:before { + content: "\f105"; } + +.fa-angle-up:before { + content: "\f106"; } + +.fa-angry:before { + content: "\f556"; } + +.fa-angrycreative:before { + content: "\f36e"; } + +.fa-angular:before { + content: "\f420"; } + +.fa-ankh:before { + content: "\f644"; } + +.fa-app-store:before { + content: "\f36f"; } + +.fa-app-store-ios:before { + content: "\f370"; } + +.fa-apper:before { + content: "\f371"; } + +.fa-apple:before { + content: "\f179"; } + +.fa-apple-alt:before { + content: "\f5d1"; } + +.fa-apple-pay:before { + content: "\f415"; } + +.fa-archive:before { + content: "\f187"; } + +.fa-archway:before { + content: "\f557"; } + +.fa-arrow-alt-circle-down:before { + content: "\f358"; } + +.fa-arrow-alt-circle-left:before { + content: "\f359"; } + +.fa-arrow-alt-circle-right:before { + content: "\f35a"; } + +.fa-arrow-alt-circle-up:before { + content: "\f35b"; } + +.fa-arrow-circle-down:before { + content: "\f0ab"; } + +.fa-arrow-circle-left:before { + content: "\f0a8"; } + +.fa-arrow-circle-right:before { + content: "\f0a9"; } + +.fa-arrow-circle-up:before { + content: "\f0aa"; } + +.fa-arrow-down:before { + content: "\f063"; } + +.fa-arrow-left:before { + content: "\f060"; } + +.fa-arrow-right:before { + content: "\f061"; } + +.fa-arrow-up:before { + content: "\f062"; } + +.fa-arrows-alt:before { + content: "\f0b2"; } + +.fa-arrows-alt-h:before { + content: "\f337"; } + +.fa-arrows-alt-v:before { + content: "\f338"; } + +.fa-artstation:before { + content: "\f77a"; } + +.fa-assistive-listening-systems:before { + content: "\f2a2"; } + +.fa-asterisk:before { + content: "\f069"; } + +.fa-asymmetrik:before { + content: "\f372"; } + +.fa-at:before { + content: "\f1fa"; } + +.fa-atlas:before { + content: "\f558"; } + +.fa-atlassian:before { + content: "\f77b"; } + +.fa-atom:before { + content: "\f5d2"; } + +.fa-audible:before { + content: "\f373"; } + +.fa-audio-description:before { + content: "\f29e"; } + +.fa-autoprefixer:before { + content: "\f41c"; } + +.fa-avianex:before { + content: "\f374"; } + +.fa-aviato:before { + content: "\f421"; } + +.fa-award:before { + content: "\f559"; } + +.fa-aws:before { + content: "\f375"; } + +.fa-baby:before { + content: "\f77c"; } + +.fa-baby-carriage:before { + content: "\f77d"; } + +.fa-backspace:before { + content: "\f55a"; } + +.fa-backward:before { + content: "\f04a"; } + +.fa-bacon:before { + content: "\f7e5"; } + +.fa-bahai:before { + content: "\f666"; } + +.fa-balance-scale:before { + content: "\f24e"; } + +.fa-balance-scale-left:before { + content: "\f515"; } + +.fa-balance-scale-right:before { + content: "\f516"; } + +.fa-ban:before { + content: "\f05e"; } + +.fa-band-aid:before { + content: "\f462"; } + +.fa-bandcamp:before { + content: "\f2d5"; } + +.fa-barcode:before { + content: "\f02a"; } + +.fa-bars:before { + content: "\f0c9"; } + +.fa-baseball-ball:before { + content: "\f433"; } + +.fa-basketball-ball:before { + content: "\f434"; } + +.fa-bath:before { + content: "\f2cd"; } + +.fa-battery-empty:before { + content: "\f244"; } + +.fa-battery-full:before { + content: "\f240"; } + +.fa-battery-half:before { + content: "\f242"; } + +.fa-battery-quarter:before { + content: "\f243"; } + +.fa-battery-three-quarters:before { + content: "\f241"; } + +.fa-battle-net:before { + content: "\f835"; } + +.fa-bed:before { + content: "\f236"; } + +.fa-beer:before { + content: "\f0fc"; } + +.fa-behance:before { + content: "\f1b4"; } + +.fa-behance-square:before { + content: "\f1b5"; } + +.fa-bell:before { + content: "\f0f3"; } + +.fa-bell-slash:before { + content: "\f1f6"; } + +.fa-bezier-curve:before { + content: "\f55b"; } + +.fa-bible:before { + content: "\f647"; } + +.fa-bicycle:before { + content: "\f206"; } + +.fa-biking:before { + content: "\f84a"; } + +.fa-bimobject:before { + content: "\f378"; } + +.fa-binoculars:before { + content: "\f1e5"; } + +.fa-biohazard:before { + content: "\f780"; } + +.fa-birthday-cake:before { + content: "\f1fd"; } + +.fa-bitbucket:before { + content: "\f171"; } + +.fa-bitcoin:before { + content: "\f379"; } + +.fa-bity:before { + content: "\f37a"; } + +.fa-black-tie:before { + content: "\f27e"; } + +.fa-blackberry:before { + content: "\f37b"; } + +.fa-blender:before { + content: "\f517"; } + +.fa-blender-phone:before { + content: "\f6b6"; } + +.fa-blind:before { + content: "\f29d"; } + +.fa-blog:before { + content: "\f781"; } + +.fa-blogger:before { + content: "\f37c"; } + +.fa-blogger-b:before { + content: "\f37d"; } + +.fa-bluetooth:before { + content: "\f293"; } + +.fa-bluetooth-b:before { + content: "\f294"; } + +.fa-bold:before { + content: "\f032"; } + +.fa-bolt:before { + content: "\f0e7"; } + +.fa-bomb:before { + content: "\f1e2"; } + +.fa-bone:before { + content: "\f5d7"; } + +.fa-bong:before { + content: "\f55c"; } + +.fa-book:before { + content: "\f02d"; } + +.fa-book-dead:before { + content: "\f6b7"; } + +.fa-book-medical:before { + content: "\f7e6"; } + +.fa-book-open:before { + content: "\f518"; } + +.fa-book-reader:before { + content: "\f5da"; } + +.fa-bookmark:before { + content: "\f02e"; } + +.fa-bootstrap:before { + content: "\f836"; } + +.fa-border-all:before { + content: "\f84c"; } + +.fa-border-none:before { + content: "\f850"; } + +.fa-border-style:before { + content: "\f853"; } + +.fa-bowling-ball:before { + content: "\f436"; } + +.fa-box:before { + content: "\f466"; } + +.fa-box-open:before { + content: "\f49e"; } + +.fa-boxes:before { + content: "\f468"; } + +.fa-braille:before { + content: "\f2a1"; } + +.fa-brain:before { + content: "\f5dc"; } + +.fa-bread-slice:before { + content: "\f7ec"; } + +.fa-briefcase:before { + content: "\f0b1"; } + +.fa-briefcase-medical:before { + content: "\f469"; } + +.fa-broadcast-tower:before { + content: "\f519"; } + +.fa-broom:before { + content: "\f51a"; } + +.fa-brush:before { + content: "\f55d"; } + +.fa-btc:before { + content: "\f15a"; } + +.fa-buffer:before { + content: "\f837"; } + +.fa-bug:before { + content: "\f188"; } + +.fa-building:before { + content: "\f1ad"; } + +.fa-bullhorn:before { + content: "\f0a1"; } + +.fa-bullseye:before { + content: "\f140"; } + +.fa-burn:before { + content: "\f46a"; } + +.fa-buromobelexperte:before { + content: "\f37f"; } + +.fa-bus:before { + content: "\f207"; } + +.fa-bus-alt:before { + content: "\f55e"; } + +.fa-business-time:before { + content: "\f64a"; } + +.fa-buy-n-large:before { + content: "\f8a6"; } + +.fa-buysellads:before { + content: "\f20d"; } + +.fa-calculator:before { + content: "\f1ec"; } + +.fa-calendar:before { + content: "\f133"; } + +.fa-calendar-alt:before { + content: "\f073"; } + +.fa-calendar-check:before { + content: "\f274"; } + +.fa-calendar-day:before { + content: "\f783"; } + +.fa-calendar-minus:before { + content: "\f272"; } + +.fa-calendar-plus:before { + content: "\f271"; } + +.fa-calendar-times:before { + content: "\f273"; } + +.fa-calendar-week:before { + content: "\f784"; } + +.fa-camera:before { + content: "\f030"; } + +.fa-camera-retro:before { + content: "\f083"; } + +.fa-campground:before { + content: "\f6bb"; } + +.fa-canadian-maple-leaf:before { + content: "\f785"; } + +.fa-candy-cane:before { + content: "\f786"; } + +.fa-cannabis:before { + content: "\f55f"; } + +.fa-capsules:before { + content: "\f46b"; } + +.fa-car:before { + content: "\f1b9"; } + +.fa-car-alt:before { + content: "\f5de"; } + +.fa-car-battery:before { + content: "\f5df"; } + +.fa-car-crash:before { + content: "\f5e1"; } + +.fa-car-side:before { + content: "\f5e4"; } + +.fa-caravan:before { + content: "\f8ff"; } + +.fa-caret-down:before { + content: "\f0d7"; } + +.fa-caret-left:before { + content: "\f0d9"; } + +.fa-caret-right:before { + content: "\f0da"; } + +.fa-caret-square-down:before { + content: "\f150"; } + +.fa-caret-square-left:before { + content: "\f191"; } + +.fa-caret-square-right:before { + content: "\f152"; } + +.fa-caret-square-up:before { + content: "\f151"; } + +.fa-caret-up:before { + content: "\f0d8"; } + +.fa-carrot:before { + content: "\f787"; } + +.fa-cart-arrow-down:before { + content: "\f218"; } + +.fa-cart-plus:before { + content: "\f217"; } + +.fa-cash-register:before { + content: "\f788"; } + +.fa-cat:before { + content: "\f6be"; } + +.fa-cc-amazon-pay:before { + content: "\f42d"; } + +.fa-cc-amex:before { + content: "\f1f3"; } + +.fa-cc-apple-pay:before { + content: "\f416"; } + +.fa-cc-diners-club:before { + content: "\f24c"; } + +.fa-cc-discover:before { + content: "\f1f2"; } + +.fa-cc-jcb:before { + content: "\f24b"; } + +.fa-cc-mastercard:before { + content: "\f1f1"; } + +.fa-cc-paypal:before { + content: "\f1f4"; } + +.fa-cc-stripe:before { + content: "\f1f5"; } + +.fa-cc-visa:before { + content: "\f1f0"; } + +.fa-centercode:before { + content: "\f380"; } + +.fa-centos:before { + content: "\f789"; } + +.fa-certificate:before { + content: "\f0a3"; } + +.fa-chair:before { + content: "\f6c0"; } + +.fa-chalkboard:before { + content: "\f51b"; } + +.fa-chalkboard-teacher:before { + content: "\f51c"; } + +.fa-charging-station:before { + content: "\f5e7"; } + +.fa-chart-area:before { + content: "\f1fe"; } + +.fa-chart-bar:before { + content: "\f080"; } + +.fa-chart-line:before { + content: "\f201"; } + +.fa-chart-pie:before { + content: "\f200"; } + +.fa-check:before { + content: "\f00c"; } + +.fa-check-circle:before { + content: "\f058"; } + +.fa-check-double:before { + content: "\f560"; } + +.fa-check-square:before { + content: "\f14a"; } + +.fa-cheese:before { + content: "\f7ef"; } + +.fa-chess:before { + content: "\f439"; } + +.fa-chess-bishop:before { + content: "\f43a"; } + +.fa-chess-board:before { + content: "\f43c"; } + +.fa-chess-king:before { + content: "\f43f"; } + +.fa-chess-knight:before { + content: "\f441"; } + +.fa-chess-pawn:before { + content: "\f443"; } + +.fa-chess-queen:before { + content: "\f445"; } + +.fa-chess-rook:before { + content: "\f447"; } + +.fa-chevron-circle-down:before { + content: "\f13a"; } + +.fa-chevron-circle-left:before { + content: "\f137"; } + +.fa-chevron-circle-right:before { + content: "\f138"; } + +.fa-chevron-circle-up:before { + content: "\f139"; } + +.fa-chevron-down:before { + content: "\f078"; } + +.fa-chevron-left:before { + content: "\f053"; } + +.fa-chevron-right:before { + content: "\f054"; } + +.fa-chevron-up:before { + content: "\f077"; } + +.fa-child:before { + content: "\f1ae"; } + +.fa-chrome:before { + content: "\f268"; } + +.fa-chromecast:before { + content: "\f838"; } + +.fa-church:before { + content: "\f51d"; } + +.fa-circle:before { + content: "\f111"; } + +.fa-circle-notch:before { + content: "\f1ce"; } + +.fa-city:before { + content: "\f64f"; } + +.fa-clinic-medical:before { + content: "\f7f2"; } + +.fa-clipboard:before { + content: "\f328"; } + +.fa-clipboard-check:before { + content: "\f46c"; } + +.fa-clipboard-list:before { + content: "\f46d"; } + +.fa-clock:before { + content: "\f017"; } + +.fa-clone:before { + content: "\f24d"; } + +.fa-closed-captioning:before { + content: "\f20a"; } + +.fa-cloud:before { + content: "\f0c2"; } + +.fa-cloud-download-alt:before { + content: "\f381"; } + +.fa-cloud-meatball:before { + content: "\f73b"; } + +.fa-cloud-moon:before { + content: "\f6c3"; } + +.fa-cloud-moon-rain:before { + content: "\f73c"; } + +.fa-cloud-rain:before { + content: "\f73d"; } + +.fa-cloud-showers-heavy:before { + content: "\f740"; } + +.fa-cloud-sun:before { + content: "\f6c4"; } + +.fa-cloud-sun-rain:before { + content: "\f743"; } + +.fa-cloud-upload-alt:before { + content: "\f382"; } + +.fa-cloudscale:before { + content: "\f383"; } + +.fa-cloudsmith:before { + content: "\f384"; } + +.fa-cloudversify:before { + content: "\f385"; } + +.fa-cocktail:before { + content: "\f561"; } + +.fa-code:before { + content: "\f121"; } + +.fa-code-branch:before { + content: "\f126"; } + +.fa-codepen:before { + content: "\f1cb"; } + +.fa-codiepie:before { + content: "\f284"; } + +.fa-coffee:before { + content: "\f0f4"; } + +.fa-cog:before { + content: "\f013"; } + +.fa-cogs:before { + content: "\f085"; } + +.fa-coins:before { + content: "\f51e"; } + +.fa-columns:before { + content: "\f0db"; } + +.fa-comment:before { + content: "\f075"; } + +.fa-comment-alt:before { + content: "\f27a"; } + +.fa-comment-dollar:before { + content: "\f651"; } + +.fa-comment-dots:before { + content: "\f4ad"; } + +.fa-comment-medical:before { + content: "\f7f5"; } + +.fa-comment-slash:before { + content: "\f4b3"; } + +.fa-comments:before { + content: "\f086"; } + +.fa-comments-dollar:before { + content: "\f653"; } + +.fa-compact-disc:before { + content: "\f51f"; } + +.fa-compass:before { + content: "\f14e"; } + +.fa-compress:before { + content: "\f066"; } + +.fa-compress-alt:before { + content: "\f422"; } + +.fa-compress-arrows-alt:before { + content: "\f78c"; } + +.fa-concierge-bell:before { + content: "\f562"; } + +.fa-confluence:before { + content: "\f78d"; } + +.fa-connectdevelop:before { + content: "\f20e"; } + +.fa-contao:before { + content: "\f26d"; } + +.fa-cookie:before { + content: "\f563"; } + +.fa-cookie-bite:before { + content: "\f564"; } + +.fa-copy:before { + content: "\f0c5"; } + +.fa-copyright:before { + content: "\f1f9"; } + +.fa-cotton-bureau:before { + content: "\f89e"; } + +.fa-couch:before { + content: "\f4b8"; } + +.fa-cpanel:before { + content: "\f388"; } + +.fa-creative-commons:before { + content: "\f25e"; } + +.fa-creative-commons-by:before { + content: "\f4e7"; } + +.fa-creative-commons-nc:before { + content: "\f4e8"; } + +.fa-creative-commons-nc-eu:before { + content: "\f4e9"; } + +.fa-creative-commons-nc-jp:before { + content: "\f4ea"; } + +.fa-creative-commons-nd:before { + content: "\f4eb"; } + +.fa-creative-commons-pd:before { + content: "\f4ec"; } + +.fa-creative-commons-pd-alt:before { + content: "\f4ed"; } + +.fa-creative-commons-remix:before { + content: "\f4ee"; } + +.fa-creative-commons-sa:before { + content: "\f4ef"; } + +.fa-creative-commons-sampling:before { + content: "\f4f0"; } + +.fa-creative-commons-sampling-plus:before { + content: "\f4f1"; } + +.fa-creative-commons-share:before { + content: "\f4f2"; } + +.fa-creative-commons-zero:before { + content: "\f4f3"; } + +.fa-credit-card:before { + content: "\f09d"; } + +.fa-critical-role:before { + content: "\f6c9"; } + +.fa-crop:before { + content: "\f125"; } + +.fa-crop-alt:before { + content: "\f565"; } + +.fa-cross:before { + content: "\f654"; } + +.fa-crosshairs:before { + content: "\f05b"; } + +.fa-crow:before { + content: "\f520"; } + +.fa-crown:before { + content: "\f521"; } + +.fa-crutch:before { + content: "\f7f7"; } + +.fa-css3:before { + content: "\f13c"; } + +.fa-css3-alt:before { + content: "\f38b"; } + +.fa-cube:before { + content: "\f1b2"; } + +.fa-cubes:before { + content: "\f1b3"; } + +.fa-cut:before { + content: "\f0c4"; } + +.fa-cuttlefish:before { + content: "\f38c"; } + +.fa-d-and-d:before { + content: "\f38d"; } + +.fa-d-and-d-beyond:before { + content: "\f6ca"; } + +.fa-dashcube:before { + content: "\f210"; } + +.fa-database:before { + content: "\f1c0"; } + +.fa-deaf:before { + content: "\f2a4"; } + +.fa-delicious:before { + content: "\f1a5"; } + +.fa-democrat:before { + content: "\f747"; } + +.fa-deploydog:before { + content: "\f38e"; } + +.fa-deskpro:before { + content: "\f38f"; } + +.fa-desktop:before { + content: "\f108"; } + +.fa-dev:before { + content: "\f6cc"; } + +.fa-deviantart:before { + content: "\f1bd"; } + +.fa-dharmachakra:before { + content: "\f655"; } + +.fa-dhl:before { + content: "\f790"; } + +.fa-diagnoses:before { + content: "\f470"; } + +.fa-diaspora:before { + content: "\f791"; } + +.fa-dice:before { + content: "\f522"; } + +.fa-dice-d20:before { + content: "\f6cf"; } + +.fa-dice-d6:before { + content: "\f6d1"; } + +.fa-dice-five:before { + content: "\f523"; } + +.fa-dice-four:before { + content: "\f524"; } + +.fa-dice-one:before { + content: "\f525"; } + +.fa-dice-six:before { + content: "\f526"; } + +.fa-dice-three:before { + content: "\f527"; } + +.fa-dice-two:before { + content: "\f528"; } + +.fa-digg:before { + content: "\f1a6"; } + +.fa-digital-ocean:before { + content: "\f391"; } + +.fa-digital-tachograph:before { + content: "\f566"; } + +.fa-directions:before { + content: "\f5eb"; } + +.fa-discord:before { + content: "\f392"; } + +.fa-discourse:before { + content: "\f393"; } + +.fa-divide:before { + content: "\f529"; } + +.fa-dizzy:before { + content: "\f567"; } + +.fa-dna:before { + content: "\f471"; } + +.fa-dochub:before { + content: "\f394"; } + +.fa-docker:before { + content: "\f395"; } + +.fa-dog:before { + content: "\f6d3"; } + +.fa-dollar-sign:before { + content: "\f155"; } + +.fa-dolly:before { + content: "\f472"; } + +.fa-dolly-flatbed:before { + content: "\f474"; } + +.fa-donate:before { + content: "\f4b9"; } + +.fa-door-closed:before { + content: "\f52a"; } + +.fa-door-open:before { + content: "\f52b"; } + +.fa-dot-circle:before { + content: "\f192"; } + +.fa-dove:before { + content: "\f4ba"; } + +.fa-download:before { + content: "\f019"; } + +.fa-draft2digital:before { + content: "\f396"; } + +.fa-drafting-compass:before { + content: "\f568"; } + +.fa-dragon:before { + content: "\f6d5"; } + +.fa-draw-polygon:before { + content: "\f5ee"; } + +.fa-dribbble:before { + content: "\f17d"; } + +.fa-dribbble-square:before { + content: "\f397"; } + +.fa-dropbox:before { + content: "\f16b"; } + +.fa-drum:before { + content: "\f569"; } + +.fa-drum-steelpan:before { + content: "\f56a"; } + +.fa-drumstick-bite:before { + content: "\f6d7"; } + +.fa-drupal:before { + content: "\f1a9"; } + +.fa-dumbbell:before { + content: "\f44b"; } + +.fa-dumpster:before { + content: "\f793"; } + +.fa-dumpster-fire:before { + content: "\f794"; } + +.fa-dungeon:before { + content: "\f6d9"; } + +.fa-dyalog:before { + content: "\f399"; } + +.fa-earlybirds:before { + content: "\f39a"; } + +.fa-ebay:before { + content: "\f4f4"; } + +.fa-edge:before { + content: "\f282"; } + +.fa-edit:before { + content: "\f044"; } + +.fa-egg:before { + content: "\f7fb"; } + +.fa-eject:before { + content: "\f052"; } + +.fa-elementor:before { + content: "\f430"; } + +.fa-ellipsis-h:before { + content: "\f141"; } + +.fa-ellipsis-v:before { + content: "\f142"; } + +.fa-ello:before { + content: "\f5f1"; } + +.fa-ember:before { + content: "\f423"; } + +.fa-empire:before { + content: "\f1d1"; } + +.fa-envelope:before { + content: "\f0e0"; } + +.fa-envelope-open:before { + content: "\f2b6"; } + +.fa-envelope-open-text:before { + content: "\f658"; } + +.fa-envelope-square:before { + content: "\f199"; } + +.fa-envira:before { + content: "\f299"; } + +.fa-equals:before { + content: "\f52c"; } + +.fa-eraser:before { + content: "\f12d"; } + +.fa-erlang:before { + content: "\f39d"; } + +.fa-ethereum:before { + content: "\f42e"; } + +.fa-ethernet:before { + content: "\f796"; } + +.fa-etsy:before { + content: "\f2d7"; } + +.fa-euro-sign:before { + content: "\f153"; } + +.fa-evernote:before { + content: "\f839"; } + +.fa-exchange-alt:before { + content: "\f362"; } + +.fa-exclamation:before { + content: "\f12a"; } + +.fa-exclamation-circle:before { + content: "\f06a"; } + +.fa-exclamation-triangle:before { + content: "\f071"; } + +.fa-expand:before { + content: "\f065"; } + +.fa-expand-alt:before { + content: "\f424"; } + +.fa-expand-arrows-alt:before { + content: "\f31e"; } + +.fa-expeditedssl:before { + content: "\f23e"; } + +.fa-external-link-alt:before { + content: "\f35d"; } + +.fa-external-link-square-alt:before { + content: "\f360"; } + +.fa-eye:before { + content: "\f06e"; } + +.fa-eye-dropper:before { + content: "\f1fb"; } + +.fa-eye-slash:before { + content: "\f070"; } + +.fa-facebook:before { + content: "\f09a"; } + +.fa-facebook-f:before { + content: "\f39e"; } + +.fa-facebook-messenger:before { + content: "\f39f"; } + +.fa-facebook-square:before { + content: "\f082"; } + +.fa-fan:before { + content: "\f863"; } + +.fa-fantasy-flight-games:before { + content: "\f6dc"; } + +.fa-fast-backward:before { + content: "\f049"; } + +.fa-fast-forward:before { + content: "\f050"; } + +.fa-fax:before { + content: "\f1ac"; } + +.fa-feather:before { + content: "\f52d"; } + +.fa-feather-alt:before { + content: "\f56b"; } + +.fa-fedex:before { + content: "\f797"; } + +.fa-fedora:before { + content: "\f798"; } + +.fa-female:before { + content: "\f182"; } + +.fa-fighter-jet:before { + content: "\f0fb"; } + +.fa-figma:before { + content: "\f799"; } + +.fa-file:before { + content: "\f15b"; } + +.fa-file-alt:before { + content: "\f15c"; } + +.fa-file-archive:before { + content: "\f1c6"; } + +.fa-file-audio:before { + content: "\f1c7"; } + +.fa-file-code:before { + content: "\f1c9"; } + +.fa-file-contract:before { + content: "\f56c"; } + +.fa-file-csv:before { + content: "\f6dd"; } + +.fa-file-download:before { + content: "\f56d"; } + +.fa-file-excel:before { + content: "\f1c3"; } + +.fa-file-export:before { + content: "\f56e"; } + +.fa-file-image:before { + content: "\f1c5"; } + +.fa-file-import:before { + content: "\f56f"; } + +.fa-file-invoice:before { + content: "\f570"; } + +.fa-file-invoice-dollar:before { + content: "\f571"; } + +.fa-file-medical:before { + content: "\f477"; } + +.fa-file-medical-alt:before { + content: "\f478"; } + +.fa-file-pdf:before { + content: "\f1c1"; } + +.fa-file-powerpoint:before { + content: "\f1c4"; } + +.fa-file-prescription:before { + content: "\f572"; } + +.fa-file-signature:before { + content: "\f573"; } + +.fa-file-upload:before { + content: "\f574"; } + +.fa-file-video:before { + content: "\f1c8"; } + +.fa-file-word:before { + content: "\f1c2"; } + +.fa-fill:before { + content: "\f575"; } + +.fa-fill-drip:before { + content: "\f576"; } + +.fa-film:before { + content: "\f008"; } + +.fa-filter:before { + content: "\f0b0"; } + +.fa-fingerprint:before { + content: "\f577"; } + +.fa-fire:before { + content: "\f06d"; } + +.fa-fire-alt:before { + content: "\f7e4"; } + +.fa-fire-extinguisher:before { + content: "\f134"; } + +.fa-firefox:before { + content: "\f269"; } + +.fa-firefox-browser:before { + content: "\f907"; } + +.fa-first-aid:before { + content: "\f479"; } + +.fa-first-order:before { + content: "\f2b0"; } + +.fa-first-order-alt:before { + content: "\f50a"; } + +.fa-firstdraft:before { + content: "\f3a1"; } + +.fa-fish:before { + content: "\f578"; } + +.fa-fist-raised:before { + content: "\f6de"; } + +.fa-flag:before { + content: "\f024"; } + +.fa-flag-checkered:before { + content: "\f11e"; } + +.fa-flag-usa:before { + content: "\f74d"; } + +.fa-flask:before { + content: "\f0c3"; } + +.fa-flickr:before { + content: "\f16e"; } + +.fa-flipboard:before { + content: "\f44d"; } + +.fa-flushed:before { + content: "\f579"; } + +.fa-fly:before { + content: "\f417"; } + +.fa-folder:before { + content: "\f07b"; } + +.fa-folder-minus:before { + content: "\f65d"; } + +.fa-folder-open:before { + content: "\f07c"; } + +.fa-folder-plus:before { + content: "\f65e"; } + +.fa-font:before { + content: "\f031"; } + +.fa-font-awesome:before { + content: "\f2b4"; } + +.fa-font-awesome-alt:before { + content: "\f35c"; } + +.fa-font-awesome-flag:before { + content: "\f425"; } + +.fa-font-awesome-logo-full:before { + content: "\f4e6"; } + +.fa-fonticons:before { + content: "\f280"; } + +.fa-fonticons-fi:before { + content: "\f3a2"; } + +.fa-football-ball:before { + content: "\f44e"; } + +.fa-fort-awesome:before { + content: "\f286"; } + +.fa-fort-awesome-alt:before { + content: "\f3a3"; } + +.fa-forumbee:before { + content: "\f211"; } + +.fa-forward:before { + content: "\f04e"; } + +.fa-foursquare:before { + content: "\f180"; } + +.fa-free-code-camp:before { + content: "\f2c5"; } + +.fa-freebsd:before { + content: "\f3a4"; } + +.fa-frog:before { + content: "\f52e"; } + +.fa-frown:before { + content: "\f119"; } + +.fa-frown-open:before { + content: "\f57a"; } + +.fa-fulcrum:before { + content: "\f50b"; } + +.fa-funnel-dollar:before { + content: "\f662"; } + +.fa-futbol:before { + content: "\f1e3"; } + +.fa-galactic-republic:before { + content: "\f50c"; } + +.fa-galactic-senate:before { + content: "\f50d"; } + +.fa-gamepad:before { + content: "\f11b"; } + +.fa-gas-pump:before { + content: "\f52f"; } + +.fa-gavel:before { + content: "\f0e3"; } + +.fa-gem:before { + content: "\f3a5"; } + +.fa-genderless:before { + content: "\f22d"; } + +.fa-get-pocket:before { + content: "\f265"; } + +.fa-gg:before { + content: "\f260"; } + +.fa-gg-circle:before { + content: "\f261"; } + +.fa-ghost:before { + content: "\f6e2"; } + +.fa-gift:before { + content: "\f06b"; } + +.fa-gifts:before { + content: "\f79c"; } + +.fa-git:before { + content: "\f1d3"; } + +.fa-git-alt:before { + content: "\f841"; } + +.fa-git-square:before { + content: "\f1d2"; } + +.fa-github:before { + content: "\f09b"; } + +.fa-github-alt:before { + content: "\f113"; } + +.fa-github-square:before { + content: "\f092"; } + +.fa-gitkraken:before { + content: "\f3a6"; } + +.fa-gitlab:before { + content: "\f296"; } + +.fa-gitter:before { + content: "\f426"; } + +.fa-glass-cheers:before { + content: "\f79f"; } + +.fa-glass-martini:before { + content: "\f000"; } + +.fa-glass-martini-alt:before { + content: "\f57b"; } + +.fa-glass-whiskey:before { + content: "\f7a0"; } + +.fa-glasses:before { + content: "\f530"; } + +.fa-glide:before { + content: "\f2a5"; } + +.fa-glide-g:before { + content: "\f2a6"; } + +.fa-globe:before { + content: "\f0ac"; } + +.fa-globe-africa:before { + content: "\f57c"; } + +.fa-globe-americas:before { + content: "\f57d"; } + +.fa-globe-asia:before { + content: "\f57e"; } + +.fa-globe-europe:before { + content: "\f7a2"; } + +.fa-gofore:before { + content: "\f3a7"; } + +.fa-golf-ball:before { + content: "\f450"; } + +.fa-goodreads:before { + content: "\f3a8"; } + +.fa-goodreads-g:before { + content: "\f3a9"; } + +.fa-google:before { + content: "\f1a0"; } + +.fa-google-drive:before { + content: "\f3aa"; } + +.fa-google-play:before { + content: "\f3ab"; } + +.fa-google-plus:before { + content: "\f2b3"; } + +.fa-google-plus-g:before { + content: "\f0d5"; } + +.fa-google-plus-square:before { + content: "\f0d4"; } + +.fa-google-wallet:before { + content: "\f1ee"; } + +.fa-gopuram:before { + content: "\f664"; } + +.fa-graduation-cap:before { + content: "\f19d"; } + +.fa-gratipay:before { + content: "\f184"; } + +.fa-grav:before { + content: "\f2d6"; } + +.fa-greater-than:before { + content: "\f531"; } + +.fa-greater-than-equal:before { + content: "\f532"; } + +.fa-grimace:before { + content: "\f57f"; } + +.fa-grin:before { + content: "\f580"; } + +.fa-grin-alt:before { + content: "\f581"; } + +.fa-grin-beam:before { + content: "\f582"; } + +.fa-grin-beam-sweat:before { + content: "\f583"; } + +.fa-grin-hearts:before { + content: "\f584"; } + +.fa-grin-squint:before { + content: "\f585"; } + +.fa-grin-squint-tears:before { + content: "\f586"; } + +.fa-grin-stars:before { + content: "\f587"; } + +.fa-grin-tears:before { + content: "\f588"; } + +.fa-grin-tongue:before { + content: "\f589"; } + +.fa-grin-tongue-squint:before { + content: "\f58a"; } + +.fa-grin-tongue-wink:before { + content: "\f58b"; } + +.fa-grin-wink:before { + content: "\f58c"; } + +.fa-grip-horizontal:before { + content: "\f58d"; } + +.fa-grip-lines:before { + content: "\f7a4"; } + +.fa-grip-lines-vertical:before { + content: "\f7a5"; } + +.fa-grip-vertical:before { + content: "\f58e"; } + +.fa-gripfire:before { + content: "\f3ac"; } + +.fa-grunt:before { + content: "\f3ad"; } + +.fa-guitar:before { + content: "\f7a6"; } + +.fa-gulp:before { + content: "\f3ae"; } + +.fa-h-square:before { + content: "\f0fd"; } + +.fa-hacker-news:before { + content: "\f1d4"; } + +.fa-hacker-news-square:before { + content: "\f3af"; } + +.fa-hackerrank:before { + content: "\f5f7"; } + +.fa-hamburger:before { + content: "\f805"; } + +.fa-hammer:before { + content: "\f6e3"; } + +.fa-hamsa:before { + content: "\f665"; } + +.fa-hand-holding:before { + content: "\f4bd"; } + +.fa-hand-holding-heart:before { + content: "\f4be"; } + +.fa-hand-holding-usd:before { + content: "\f4c0"; } + +.fa-hand-lizard:before { + content: "\f258"; } + +.fa-hand-middle-finger:before { + content: "\f806"; } + +.fa-hand-paper:before { + content: "\f256"; } + +.fa-hand-peace:before { + content: "\f25b"; } + +.fa-hand-point-down:before { + content: "\f0a7"; } + +.fa-hand-point-left:before { + content: "\f0a5"; } + +.fa-hand-point-right:before { + content: "\f0a4"; } + +.fa-hand-point-up:before { + content: "\f0a6"; } + +.fa-hand-pointer:before { + content: "\f25a"; } + +.fa-hand-rock:before { + content: "\f255"; } + +.fa-hand-scissors:before { + content: "\f257"; } + +.fa-hand-spock:before { + content: "\f259"; } + +.fa-hands:before { + content: "\f4c2"; } + +.fa-hands-helping:before { + content: "\f4c4"; } + +.fa-handshake:before { + content: "\f2b5"; } + +.fa-hanukiah:before { + content: "\f6e6"; } + +.fa-hard-hat:before { + content: "\f807"; } + +.fa-hashtag:before { + content: "\f292"; } + +.fa-hat-cowboy:before { + content: "\f8c0"; } + +.fa-hat-cowboy-side:before { + content: "\f8c1"; } + +.fa-hat-wizard:before { + content: "\f6e8"; } + +.fa-hdd:before { + content: "\f0a0"; } + +.fa-heading:before { + content: "\f1dc"; } + +.fa-headphones:before { + content: "\f025"; } + +.fa-headphones-alt:before { + content: "\f58f"; } + +.fa-headset:before { + content: "\f590"; } + +.fa-heart:before { + content: "\f004"; } + +.fa-heart-broken:before { + content: "\f7a9"; } + +.fa-heartbeat:before { + content: "\f21e"; } + +.fa-helicopter:before { + content: "\f533"; } + +.fa-highlighter:before { + content: "\f591"; } + +.fa-hiking:before { + content: "\f6ec"; } + +.fa-hippo:before { + content: "\f6ed"; } + +.fa-hips:before { + content: "\f452"; } + +.fa-hire-a-helper:before { + content: "\f3b0"; } + +.fa-history:before { + content: "\f1da"; } + +.fa-hockey-puck:before { + content: "\f453"; } + +.fa-holly-berry:before { + content: "\f7aa"; } + +.fa-home:before { + content: "\f015"; } + +.fa-hooli:before { + content: "\f427"; } + +.fa-hornbill:before { + content: "\f592"; } + +.fa-horse:before { + content: "\f6f0"; } + +.fa-horse-head:before { + content: "\f7ab"; } + +.fa-hospital:before { + content: "\f0f8"; } + +.fa-hospital-alt:before { + content: "\f47d"; } + +.fa-hospital-symbol:before { + content: "\f47e"; } + +.fa-hot-tub:before { + content: "\f593"; } + +.fa-hotdog:before { + content: "\f80f"; } + +.fa-hotel:before { + content: "\f594"; } + +.fa-hotjar:before { + content: "\f3b1"; } + +.fa-hourglass:before { + content: "\f254"; } + +.fa-hourglass-end:before { + content: "\f253"; } + +.fa-hourglass-half:before { + content: "\f252"; } + +.fa-hourglass-start:before { + content: "\f251"; } + +.fa-house-damage:before { + content: "\f6f1"; } + +.fa-houzz:before { + content: "\f27c"; } + +.fa-hryvnia:before { + content: "\f6f2"; } + +.fa-html5:before { + content: "\f13b"; } + +.fa-hubspot:before { + content: "\f3b2"; } + +.fa-i-cursor:before { + content: "\f246"; } + +.fa-ice-cream:before { + content: "\f810"; } + +.fa-icicles:before { + content: "\f7ad"; } + +.fa-icons:before { + content: "\f86d"; } + +.fa-id-badge:before { + content: "\f2c1"; } + +.fa-id-card:before { + content: "\f2c2"; } + +.fa-id-card-alt:before { + content: "\f47f"; } + +.fa-ideal:before { + content: "\f913"; } + +.fa-igloo:before { + content: "\f7ae"; } + +.fa-image:before { + content: "\f03e"; } + +.fa-images:before { + content: "\f302"; } + +.fa-imdb:before { + content: "\f2d8"; } + +.fa-inbox:before { + content: "\f01c"; } + +.fa-indent:before { + content: "\f03c"; } + +.fa-industry:before { + content: "\f275"; } + +.fa-infinity:before { + content: "\f534"; } + +.fa-info:before { + content: "\f129"; } + +.fa-info-circle:before { + content: "\f05a"; } + +.fa-instagram:before { + content: "\f16d"; } + +.fa-intercom:before { + content: "\f7af"; } + +.fa-internet-explorer:before { + content: "\f26b"; } + +.fa-invision:before { + content: "\f7b0"; } + +.fa-ioxhost:before { + content: "\f208"; } + +.fa-italic:before { + content: "\f033"; } + +.fa-itch-io:before { + content: "\f83a"; } + +.fa-itunes:before { + content: "\f3b4"; } + +.fa-itunes-note:before { + content: "\f3b5"; } + +.fa-java:before { + content: "\f4e4"; } + +.fa-jedi:before { + content: "\f669"; } + +.fa-jedi-order:before { + content: "\f50e"; } + +.fa-jenkins:before { + content: "\f3b6"; } + +.fa-jira:before { + content: "\f7b1"; } + +.fa-joget:before { + content: "\f3b7"; } + +.fa-joint:before { + content: "\f595"; } + +.fa-joomla:before { + content: "\f1aa"; } + +.fa-journal-whills:before { + content: "\f66a"; } + +.fa-js:before { + content: "\f3b8"; } + +.fa-js-square:before { + content: "\f3b9"; } + +.fa-jsfiddle:before { + content: "\f1cc"; } + +.fa-kaaba:before { + content: "\f66b"; } + +.fa-kaggle:before { + content: "\f5fa"; } + +.fa-key:before { + content: "\f084"; } + +.fa-keybase:before { + content: "\f4f5"; } + +.fa-keyboard:before { + content: "\f11c"; } + +.fa-keycdn:before { + content: "\f3ba"; } + +.fa-khanda:before { + content: "\f66d"; } + +.fa-kickstarter:before { + content: "\f3bb"; } + +.fa-kickstarter-k:before { + content: "\f3bc"; } + +.fa-kiss:before { + content: "\f596"; } + +.fa-kiss-beam:before { + content: "\f597"; } + +.fa-kiss-wink-heart:before { + content: "\f598"; } + +.fa-kiwi-bird:before { + content: "\f535"; } + +.fa-korvue:before { + content: "\f42f"; } + +.fa-landmark:before { + content: "\f66f"; } + +.fa-language:before { + content: "\f1ab"; } + +.fa-laptop:before { + content: "\f109"; } + +.fa-laptop-code:before { + content: "\f5fc"; } + +.fa-laptop-medical:before { + content: "\f812"; } + +.fa-laravel:before { + content: "\f3bd"; } + +.fa-lastfm:before { + content: "\f202"; } + +.fa-lastfm-square:before { + content: "\f203"; } + +.fa-laugh:before { + content: "\f599"; } + +.fa-laugh-beam:before { + content: "\f59a"; } + +.fa-laugh-squint:before { + content: "\f59b"; } + +.fa-laugh-wink:before { + content: "\f59c"; } + +.fa-layer-group:before { + content: "\f5fd"; } + +.fa-leaf:before { + content: "\f06c"; } + +.fa-leanpub:before { + content: "\f212"; } + +.fa-lemon:before { + content: "\f094"; } + +.fa-less:before { + content: "\f41d"; } + +.fa-less-than:before { + content: "\f536"; } + +.fa-less-than-equal:before { + content: "\f537"; } + +.fa-level-down-alt:before { + content: "\f3be"; } + +.fa-level-up-alt:before { + content: "\f3bf"; } + +.fa-life-ring:before { + content: "\f1cd"; } + +.fa-lightbulb:before { + content: "\f0eb"; } + +.fa-line:before { + content: "\f3c0"; } + +.fa-link:before { + content: "\f0c1"; } + +.fa-linkedin:before { + content: "\f08c"; } + +.fa-linkedin-in:before { + content: "\f0e1"; } + +.fa-linode:before { + content: "\f2b8"; } + +.fa-linux:before { + content: "\f17c"; } + +.fa-lira-sign:before { + content: "\f195"; } + +.fa-list:before { + content: "\f03a"; } + +.fa-list-alt:before { + content: "\f022"; } + +.fa-list-ol:before { + content: "\f0cb"; } + +.fa-list-ul:before { + content: "\f0ca"; } + +.fa-location-arrow:before { + content: "\f124"; } + +.fa-lock:before { + content: "\f023"; } + +.fa-lock-open:before { + content: "\f3c1"; } + +.fa-long-arrow-alt-down:before { + content: "\f309"; } + +.fa-long-arrow-alt-left:before { + content: "\f30a"; } + +.fa-long-arrow-alt-right:before { + content: "\f30b"; } + +.fa-long-arrow-alt-up:before { + content: "\f30c"; } + +.fa-low-vision:before { + content: "\f2a8"; } + +.fa-luggage-cart:before { + content: "\f59d"; } + +.fa-lyft:before { + content: "\f3c3"; } + +.fa-magento:before { + content: "\f3c4"; } + +.fa-magic:before { + content: "\f0d0"; } + +.fa-magnet:before { + content: "\f076"; } + +.fa-mail-bulk:before { + content: "\f674"; } + +.fa-mailchimp:before { + content: "\f59e"; } + +.fa-male:before { + content: "\f183"; } + +.fa-mandalorian:before { + content: "\f50f"; } + +.fa-map:before { + content: "\f279"; } + +.fa-map-marked:before { + content: "\f59f"; } + +.fa-map-marked-alt:before { + content: "\f5a0"; } + +.fa-map-marker:before { + content: "\f041"; } + +.fa-map-marker-alt:before { + content: "\f3c5"; } + +.fa-map-pin:before { + content: "\f276"; } + +.fa-map-signs:before { + content: "\f277"; } + +.fa-markdown:before { + content: "\f60f"; } + +.fa-marker:before { + content: "\f5a1"; } + +.fa-mars:before { + content: "\f222"; } + +.fa-mars-double:before { + content: "\f227"; } + +.fa-mars-stroke:before { + content: "\f229"; } + +.fa-mars-stroke-h:before { + content: "\f22b"; } + +.fa-mars-stroke-v:before { + content: "\f22a"; } + +.fa-mask:before { + content: "\f6fa"; } + +.fa-mastodon:before { + content: "\f4f6"; } + +.fa-maxcdn:before { + content: "\f136"; } + +.fa-mdb:before { + content: "\f8ca"; } + +.fa-medal:before { + content: "\f5a2"; } + +.fa-medapps:before { + content: "\f3c6"; } + +.fa-medium:before { + content: "\f23a"; } + +.fa-medium-m:before { + content: "\f3c7"; } + +.fa-medkit:before { + content: "\f0fa"; } + +.fa-medrt:before { + content: "\f3c8"; } + +.fa-meetup:before { + content: "\f2e0"; } + +.fa-megaport:before { + content: "\f5a3"; } + +.fa-meh:before { + content: "\f11a"; } + +.fa-meh-blank:before { + content: "\f5a4"; } + +.fa-meh-rolling-eyes:before { + content: "\f5a5"; } + +.fa-memory:before { + content: "\f538"; } + +.fa-mendeley:before { + content: "\f7b3"; } + +.fa-menorah:before { + content: "\f676"; } + +.fa-mercury:before { + content: "\f223"; } + +.fa-meteor:before { + content: "\f753"; } + +.fa-microblog:before { + content: "\f91a"; } + +.fa-microchip:before { + content: "\f2db"; } + +.fa-microphone:before { + content: "\f130"; } + +.fa-microphone-alt:before { + content: "\f3c9"; } + +.fa-microphone-alt-slash:before { + content: "\f539"; } + +.fa-microphone-slash:before { + content: "\f131"; } + +.fa-microscope:before { + content: "\f610"; } + +.fa-microsoft:before { + content: "\f3ca"; } + +.fa-minus:before { + content: "\f068"; } + +.fa-minus-circle:before { + content: "\f056"; } + +.fa-minus-square:before { + content: "\f146"; } + +.fa-mitten:before { + content: "\f7b5"; } + +.fa-mix:before { + content: "\f3cb"; } + +.fa-mixcloud:before { + content: "\f289"; } + +.fa-mizuni:before { + content: "\f3cc"; } + +.fa-mobile:before { + content: "\f10b"; } + +.fa-mobile-alt:before { + content: "\f3cd"; } + +.fa-modx:before { + content: "\f285"; } + +.fa-monero:before { + content: "\f3d0"; } + +.fa-money-bill:before { + content: "\f0d6"; } + +.fa-money-bill-alt:before { + content: "\f3d1"; } + +.fa-money-bill-wave:before { + content: "\f53a"; } + +.fa-money-bill-wave-alt:before { + content: "\f53b"; } + +.fa-money-check:before { + content: "\f53c"; } + +.fa-money-check-alt:before { + content: "\f53d"; } + +.fa-monument:before { + content: "\f5a6"; } + +.fa-moon:before { + content: "\f186"; } + +.fa-mortar-pestle:before { + content: "\f5a7"; } + +.fa-mosque:before { + content: "\f678"; } + +.fa-motorcycle:before { + content: "\f21c"; } + +.fa-mountain:before { + content: "\f6fc"; } + +.fa-mouse:before { + content: "\f8cc"; } + +.fa-mouse-pointer:before { + content: "\f245"; } + +.fa-mug-hot:before { + content: "\f7b6"; } + +.fa-music:before { + content: "\f001"; } + +.fa-napster:before { + content: "\f3d2"; } + +.fa-neos:before { + content: "\f612"; } + +.fa-network-wired:before { + content: "\f6ff"; } + +.fa-neuter:before { + content: "\f22c"; } + +.fa-newspaper:before { + content: "\f1ea"; } + +.fa-nimblr:before { + content: "\f5a8"; } + +.fa-node:before { + content: "\f419"; } + +.fa-node-js:before { + content: "\f3d3"; } + +.fa-not-equal:before { + content: "\f53e"; } + +.fa-notes-medical:before { + content: "\f481"; } + +.fa-npm:before { + content: "\f3d4"; } + +.fa-ns8:before { + content: "\f3d5"; } + +.fa-nutritionix:before { + content: "\f3d6"; } + +.fa-object-group:before { + content: "\f247"; } + +.fa-object-ungroup:before { + content: "\f248"; } + +.fa-odnoklassniki:before { + content: "\f263"; } + +.fa-odnoklassniki-square:before { + content: "\f264"; } + +.fa-oil-can:before { + content: "\f613"; } + +.fa-old-republic:before { + content: "\f510"; } + +.fa-om:before { + content: "\f679"; } + +.fa-opencart:before { + content: "\f23d"; } + +.fa-openid:before { + content: "\f19b"; } + +.fa-opera:before { + content: "\f26a"; } + +.fa-optin-monster:before { + content: "\f23c"; } + +.fa-orcid:before { + content: "\f8d2"; } + +.fa-osi:before { + content: "\f41a"; } + +.fa-otter:before { + content: "\f700"; } + +.fa-outdent:before { + content: "\f03b"; } + +.fa-page4:before { + content: "\f3d7"; } + +.fa-pagelines:before { + content: "\f18c"; } + +.fa-pager:before { + content: "\f815"; } + +.fa-paint-brush:before { + content: "\f1fc"; } + +.fa-paint-roller:before { + content: "\f5aa"; } + +.fa-palette:before { + content: "\f53f"; } + +.fa-palfed:before { + content: "\f3d8"; } + +.fa-pallet:before { + content: "\f482"; } + +.fa-paper-plane:before { + content: "\f1d8"; } + +.fa-paperclip:before { + content: "\f0c6"; } + +.fa-parachute-box:before { + content: "\f4cd"; } + +.fa-paragraph:before { + content: "\f1dd"; } + +.fa-parking:before { + content: "\f540"; } + +.fa-passport:before { + content: "\f5ab"; } + +.fa-pastafarianism:before { + content: "\f67b"; } + +.fa-paste:before { + content: "\f0ea"; } + +.fa-patreon:before { + content: "\f3d9"; } + +.fa-pause:before { + content: "\f04c"; } + +.fa-pause-circle:before { + content: "\f28b"; } + +.fa-paw:before { + content: "\f1b0"; } + +.fa-paypal:before { + content: "\f1ed"; } + +.fa-peace:before { + content: "\f67c"; } + +.fa-pen:before { + content: "\f304"; } + +.fa-pen-alt:before { + content: "\f305"; } + +.fa-pen-fancy:before { + content: "\f5ac"; } + +.fa-pen-nib:before { + content: "\f5ad"; } + +.fa-pen-square:before { + content: "\f14b"; } + +.fa-pencil-alt:before { + content: "\f303"; } + +.fa-pencil-ruler:before { + content: "\f5ae"; } + +.fa-penny-arcade:before { + content: "\f704"; } + +.fa-people-carry:before { + content: "\f4ce"; } + +.fa-pepper-hot:before { + content: "\f816"; } + +.fa-percent:before { + content: "\f295"; } + +.fa-percentage:before { + content: "\f541"; } + +.fa-periscope:before { + content: "\f3da"; } + +.fa-person-booth:before { + content: "\f756"; } + +.fa-phabricator:before { + content: "\f3db"; } + +.fa-phoenix-framework:before { + content: "\f3dc"; } + +.fa-phoenix-squadron:before { + content: "\f511"; } + +.fa-phone:before { + content: "\f095"; } + +.fa-phone-alt:before { + content: "\f879"; } + +.fa-phone-slash:before { + content: "\f3dd"; } + +.fa-phone-square:before { + content: "\f098"; } + +.fa-phone-square-alt:before { + content: "\f87b"; } + +.fa-phone-volume:before { + content: "\f2a0"; } + +.fa-photo-video:before { + content: "\f87c"; } + +.fa-php:before { + content: "\f457"; } + +.fa-pied-piper:before { + content: "\f2ae"; } + +.fa-pied-piper-alt:before { + content: "\f1a8"; } + +.fa-pied-piper-hat:before { + content: "\f4e5"; } + +.fa-pied-piper-pp:before { + content: "\f1a7"; } + +.fa-pied-piper-square:before { + content: "\f91e"; } + +.fa-piggy-bank:before { + content: "\f4d3"; } + +.fa-pills:before { + content: "\f484"; } + +.fa-pinterest:before { + content: "\f0d2"; } + +.fa-pinterest-p:before { + content: "\f231"; } + +.fa-pinterest-square:before { + content: "\f0d3"; } + +.fa-pizza-slice:before { + content: "\f818"; } + +.fa-place-of-worship:before { + content: "\f67f"; } + +.fa-plane:before { + content: "\f072"; } + +.fa-plane-arrival:before { + content: "\f5af"; } + +.fa-plane-departure:before { + content: "\f5b0"; } + +.fa-play:before { + content: "\f04b"; } + +.fa-play-circle:before { + content: "\f144"; } + +.fa-playstation:before { + content: "\f3df"; } + +.fa-plug:before { + content: "\f1e6"; } + +.fa-plus:before { + content: "\f067"; } + +.fa-plus-circle:before { + content: "\f055"; } + +.fa-plus-square:before { + content: "\f0fe"; } + +.fa-podcast:before { + content: "\f2ce"; } + +.fa-poll:before { + content: "\f681"; } + +.fa-poll-h:before { + content: "\f682"; } + +.fa-poo:before { + content: "\f2fe"; } + +.fa-poo-storm:before { + content: "\f75a"; } + +.fa-poop:before { + content: "\f619"; } + +.fa-portrait:before { + content: "\f3e0"; } + +.fa-pound-sign:before { + content: "\f154"; } + +.fa-power-off:before { + content: "\f011"; } + +.fa-pray:before { + content: "\f683"; } + +.fa-praying-hands:before { + content: "\f684"; } + +.fa-prescription:before { + content: "\f5b1"; } + +.fa-prescription-bottle:before { + content: "\f485"; } + +.fa-prescription-bottle-alt:before { + content: "\f486"; } + +.fa-print:before { + content: "\f02f"; } + +.fa-procedures:before { + content: "\f487"; } + +.fa-product-hunt:before { + content: "\f288"; } + +.fa-project-diagram:before { + content: "\f542"; } + +.fa-pushed:before { + content: "\f3e1"; } + +.fa-puzzle-piece:before { + content: "\f12e"; } + +.fa-python:before { + content: "\f3e2"; } + +.fa-qq:before { + content: "\f1d6"; } + +.fa-qrcode:before { + content: "\f029"; } + +.fa-question:before { + content: "\f128"; } + +.fa-question-circle:before { + content: "\f059"; } + +.fa-quidditch:before { + content: "\f458"; } + +.fa-quinscape:before { + content: "\f459"; } + +.fa-quora:before { + content: "\f2c4"; } + +.fa-quote-left:before { + content: "\f10d"; } + +.fa-quote-right:before { + content: "\f10e"; } + +.fa-quran:before { + content: "\f687"; } + +.fa-r-project:before { + content: "\f4f7"; } + +.fa-radiation:before { + content: "\f7b9"; } + +.fa-radiation-alt:before { + content: "\f7ba"; } + +.fa-rainbow:before { + content: "\f75b"; } + +.fa-random:before { + content: "\f074"; } + +.fa-raspberry-pi:before { + content: "\f7bb"; } + +.fa-ravelry:before { + content: "\f2d9"; } + +.fa-react:before { + content: "\f41b"; } + +.fa-reacteurope:before { + content: "\f75d"; } + +.fa-readme:before { + content: "\f4d5"; } + +.fa-rebel:before { + content: "\f1d0"; } + +.fa-receipt:before { + content: "\f543"; } + +.fa-record-vinyl:before { + content: "\f8d9"; } + +.fa-recycle:before { + content: "\f1b8"; } + +.fa-red-river:before { + content: "\f3e3"; } + +.fa-reddit:before { + content: "\f1a1"; } + +.fa-reddit-alien:before { + content: "\f281"; } + +.fa-reddit-square:before { + content: "\f1a2"; } + +.fa-redhat:before { + content: "\f7bc"; } + +.fa-redo:before { + content: "\f01e"; } + +.fa-redo-alt:before { + content: "\f2f9"; } + +.fa-registered:before { + content: "\f25d"; } + +.fa-remove-format:before { + content: "\f87d"; } + +.fa-renren:before { + content: "\f18b"; } + +.fa-reply:before { + content: "\f3e5"; } + +.fa-reply-all:before { + content: "\f122"; } + +.fa-replyd:before { + content: "\f3e6"; } + +.fa-republican:before { + content: "\f75e"; } + +.fa-researchgate:before { + content: "\f4f8"; } + +.fa-resolving:before { + content: "\f3e7"; } + +.fa-restroom:before { + content: "\f7bd"; } + +.fa-retweet:before { + content: "\f079"; } + +.fa-rev:before { + content: "\f5b2"; } + +.fa-ribbon:before { + content: "\f4d6"; } + +.fa-ring:before { + content: "\f70b"; } + +.fa-road:before { + content: "\f018"; } + +.fa-robot:before { + content: "\f544"; } + +.fa-rocket:before { + content: "\f135"; } + +.fa-rocketchat:before { + content: "\f3e8"; } + +.fa-rockrms:before { + content: "\f3e9"; } + +.fa-route:before { + content: "\f4d7"; } + +.fa-rss:before { + content: "\f09e"; } + +.fa-rss-square:before { + content: "\f143"; } + +.fa-ruble-sign:before { + content: "\f158"; } + +.fa-ruler:before { + content: "\f545"; } + +.fa-ruler-combined:before { + content: "\f546"; } + +.fa-ruler-horizontal:before { + content: "\f547"; } + +.fa-ruler-vertical:before { + content: "\f548"; } + +.fa-running:before { + content: "\f70c"; } + +.fa-rupee-sign:before { + content: "\f156"; } + +.fa-sad-cry:before { + content: "\f5b3"; } + +.fa-sad-tear:before { + content: "\f5b4"; } + +.fa-safari:before { + content: "\f267"; } + +.fa-salesforce:before { + content: "\f83b"; } + +.fa-sass:before { + content: "\f41e"; } + +.fa-satellite:before { + content: "\f7bf"; } + +.fa-satellite-dish:before { + content: "\f7c0"; } + +.fa-save:before { + content: "\f0c7"; } + +.fa-schlix:before { + content: "\f3ea"; } + +.fa-school:before { + content: "\f549"; } + +.fa-screwdriver:before { + content: "\f54a"; } + +.fa-scribd:before { + content: "\f28a"; } + +.fa-scroll:before { + content: "\f70e"; } + +.fa-sd-card:before { + content: "\f7c2"; } + +.fa-search:before { + content: "\f002"; } + +.fa-search-dollar:before { + content: "\f688"; } + +.fa-search-location:before { + content: "\f689"; } + +.fa-search-minus:before { + content: "\f010"; } + +.fa-search-plus:before { + content: "\f00e"; } + +.fa-searchengin:before { + content: "\f3eb"; } + +.fa-seedling:before { + content: "\f4d8"; } + +.fa-sellcast:before { + content: "\f2da"; } + +.fa-sellsy:before { + content: "\f213"; } + +.fa-server:before { + content: "\f233"; } + +.fa-servicestack:before { + content: "\f3ec"; } + +.fa-shapes:before { + content: "\f61f"; } + +.fa-share:before { + content: "\f064"; } + +.fa-share-alt:before { + content: "\f1e0"; } + +.fa-share-alt-square:before { + content: "\f1e1"; } + +.fa-share-square:before { + content: "\f14d"; } + +.fa-shekel-sign:before { + content: "\f20b"; } + +.fa-shield-alt:before { + content: "\f3ed"; } + +.fa-ship:before { + content: "\f21a"; } + +.fa-shipping-fast:before { + content: "\f48b"; } + +.fa-shirtsinbulk:before { + content: "\f214"; } + +.fa-shoe-prints:before { + content: "\f54b"; } + +.fa-shopping-bag:before { + content: "\f290"; } + +.fa-shopping-basket:before { + content: "\f291"; } + +.fa-shopping-cart:before { + content: "\f07a"; } + +.fa-shopware:before { + content: "\f5b5"; } + +.fa-shower:before { + content: "\f2cc"; } + +.fa-shuttle-van:before { + content: "\f5b6"; } + +.fa-sign:before { + content: "\f4d9"; } + +.fa-sign-in-alt:before { + content: "\f2f6"; } + +.fa-sign-language:before { + content: "\f2a7"; } + +.fa-sign-out-alt:before { + content: "\f2f5"; } + +.fa-signal:before { + content: "\f012"; } + +.fa-signature:before { + content: "\f5b7"; } + +.fa-sim-card:before { + content: "\f7c4"; } + +.fa-simplybuilt:before { + content: "\f215"; } + +.fa-sistrix:before { + content: "\f3ee"; } + +.fa-sitemap:before { + content: "\f0e8"; } + +.fa-sith:before { + content: "\f512"; } + +.fa-skating:before { + content: "\f7c5"; } + +.fa-sketch:before { + content: "\f7c6"; } + +.fa-skiing:before { + content: "\f7c9"; } + +.fa-skiing-nordic:before { + content: "\f7ca"; } + +.fa-skull:before { + content: "\f54c"; } + +.fa-skull-crossbones:before { + content: "\f714"; } + +.fa-skyatlas:before { + content: "\f216"; } + +.fa-skype:before { + content: "\f17e"; } + +.fa-slack:before { + content: "\f198"; } + +.fa-slack-hash:before { + content: "\f3ef"; } + +.fa-slash:before { + content: "\f715"; } + +.fa-sleigh:before { + content: "\f7cc"; } + +.fa-sliders-h:before { + content: "\f1de"; } + +.fa-slideshare:before { + content: "\f1e7"; } + +.fa-smile:before { + content: "\f118"; } + +.fa-smile-beam:before { + content: "\f5b8"; } + +.fa-smile-wink:before { + content: "\f4da"; } + +.fa-smog:before { + content: "\f75f"; } + +.fa-smoking:before { + content: "\f48d"; } + +.fa-smoking-ban:before { + content: "\f54d"; } + +.fa-sms:before { + content: "\f7cd"; } + +.fa-snapchat:before { + content: "\f2ab"; } + +.fa-snapchat-ghost:before { + content: "\f2ac"; } + +.fa-snapchat-square:before { + content: "\f2ad"; } + +.fa-snowboarding:before { + content: "\f7ce"; } + +.fa-snowflake:before { + content: "\f2dc"; } + +.fa-snowman:before { + content: "\f7d0"; } + +.fa-snowplow:before { + content: "\f7d2"; } + +.fa-socks:before { + content: "\f696"; } + +.fa-solar-panel:before { + content: "\f5ba"; } + +.fa-sort:before { + content: "\f0dc"; } + +.fa-sort-alpha-down:before { + content: "\f15d"; } + +.fa-sort-alpha-down-alt:before { + content: "\f881"; } + +.fa-sort-alpha-up:before { + content: "\f15e"; } + +.fa-sort-alpha-up-alt:before { + content: "\f882"; } + +.fa-sort-amount-down:before { + content: "\f160"; } + +.fa-sort-amount-down-alt:before { + content: "\f884"; } + +.fa-sort-amount-up:before { + content: "\f161"; } + +.fa-sort-amount-up-alt:before { + content: "\f885"; } + +.fa-sort-down:before { + content: "\f0dd"; } + +.fa-sort-numeric-down:before { + content: "\f162"; } + +.fa-sort-numeric-down-alt:before { + content: "\f886"; } + +.fa-sort-numeric-up:before { + content: "\f163"; } + +.fa-sort-numeric-up-alt:before { + content: "\f887"; } + +.fa-sort-up:before { + content: "\f0de"; } + +.fa-soundcloud:before { + content: "\f1be"; } + +.fa-sourcetree:before { + content: "\f7d3"; } + +.fa-spa:before { + content: "\f5bb"; } + +.fa-space-shuttle:before { + content: "\f197"; } + +.fa-speakap:before { + content: "\f3f3"; } + +.fa-speaker-deck:before { + content: "\f83c"; } + +.fa-spell-check:before { + content: "\f891"; } + +.fa-spider:before { + content: "\f717"; } + +.fa-spinner:before { + content: "\f110"; } + +.fa-splotch:before { + content: "\f5bc"; } + +.fa-spotify:before { + content: "\f1bc"; } + +.fa-spray-can:before { + content: "\f5bd"; } + +.fa-square:before { + content: "\f0c8"; } + +.fa-square-full:before { + content: "\f45c"; } + +.fa-square-root-alt:before { + content: "\f698"; } + +.fa-squarespace:before { + content: "\f5be"; } + +.fa-stack-exchange:before { + content: "\f18d"; } + +.fa-stack-overflow:before { + content: "\f16c"; } + +.fa-stackpath:before { + content: "\f842"; } + +.fa-stamp:before { + content: "\f5bf"; } + +.fa-star:before { + content: "\f005"; } + +.fa-star-and-crescent:before { + content: "\f699"; } + +.fa-star-half:before { + content: "\f089"; } + +.fa-star-half-alt:before { + content: "\f5c0"; } + +.fa-star-of-david:before { + content: "\f69a"; } + +.fa-star-of-life:before { + content: "\f621"; } + +.fa-staylinked:before { + content: "\f3f5"; } + +.fa-steam:before { + content: "\f1b6"; } + +.fa-steam-square:before { + content: "\f1b7"; } + +.fa-steam-symbol:before { + content: "\f3f6"; } + +.fa-step-backward:before { + content: "\f048"; } + +.fa-step-forward:before { + content: "\f051"; } + +.fa-stethoscope:before { + content: "\f0f1"; } + +.fa-sticker-mule:before { + content: "\f3f7"; } + +.fa-sticky-note:before { + content: "\f249"; } + +.fa-stop:before { + content: "\f04d"; } + +.fa-stop-circle:before { + content: "\f28d"; } + +.fa-stopwatch:before { + content: "\f2f2"; } + +.fa-store:before { + content: "\f54e"; } + +.fa-store-alt:before { + content: "\f54f"; } + +.fa-strava:before { + content: "\f428"; } + +.fa-stream:before { + content: "\f550"; } + +.fa-street-view:before { + content: "\f21d"; } + +.fa-strikethrough:before { + content: "\f0cc"; } + +.fa-stripe:before { + content: "\f429"; } + +.fa-stripe-s:before { + content: "\f42a"; } + +.fa-stroopwafel:before { + content: "\f551"; } + +.fa-studiovinari:before { + content: "\f3f8"; } + +.fa-stumbleupon:before { + content: "\f1a4"; } + +.fa-stumbleupon-circle:before { + content: "\f1a3"; } + +.fa-subscript:before { + content: "\f12c"; } + +.fa-subway:before { + content: "\f239"; } + +.fa-suitcase:before { + content: "\f0f2"; } + +.fa-suitcase-rolling:before { + content: "\f5c1"; } + +.fa-sun:before { + content: "\f185"; } + +.fa-superpowers:before { + content: "\f2dd"; } + +.fa-superscript:before { + content: "\f12b"; } + +.fa-supple:before { + content: "\f3f9"; } + +.fa-surprise:before { + content: "\f5c2"; } + +.fa-suse:before { + content: "\f7d6"; } + +.fa-swatchbook:before { + content: "\f5c3"; } + +.fa-swift:before { + content: "\f8e1"; } + +.fa-swimmer:before { + content: "\f5c4"; } + +.fa-swimming-pool:before { + content: "\f5c5"; } + +.fa-symfony:before { + content: "\f83d"; } + +.fa-synagogue:before { + content: "\f69b"; } + +.fa-sync:before { + content: "\f021"; } + +.fa-sync-alt:before { + content: "\f2f1"; } + +.fa-syringe:before { + content: "\f48e"; } + +.fa-table:before { + content: "\f0ce"; } + +.fa-table-tennis:before { + content: "\f45d"; } + +.fa-tablet:before { + content: "\f10a"; } + +.fa-tablet-alt:before { + content: "\f3fa"; } + +.fa-tablets:before { + content: "\f490"; } + +.fa-tachometer-alt:before { + content: "\f3fd"; } + +.fa-tag:before { + content: "\f02b"; } + +.fa-tags:before { + content: "\f02c"; } + +.fa-tape:before { + content: "\f4db"; } + +.fa-tasks:before { + content: "\f0ae"; } + +.fa-taxi:before { + content: "\f1ba"; } + +.fa-teamspeak:before { + content: "\f4f9"; } + +.fa-teeth:before { + content: "\f62e"; } + +.fa-teeth-open:before { + content: "\f62f"; } + +.fa-telegram:before { + content: "\f2c6"; } + +.fa-telegram-plane:before { + content: "\f3fe"; } + +.fa-temperature-high:before { + content: "\f769"; } + +.fa-temperature-low:before { + content: "\f76b"; } + +.fa-tencent-weibo:before { + content: "\f1d5"; } + +.fa-tenge:before { + content: "\f7d7"; } + +.fa-terminal:before { + content: "\f120"; } + +.fa-text-height:before { + content: "\f034"; } + +.fa-text-width:before { + content: "\f035"; } + +.fa-th:before { + content: "\f00a"; } + +.fa-th-large:before { + content: "\f009"; } + +.fa-th-list:before { + content: "\f00b"; } + +.fa-the-red-yeti:before { + content: "\f69d"; } + +.fa-theater-masks:before { + content: "\f630"; } + +.fa-themeco:before { + content: "\f5c6"; } + +.fa-themeisle:before { + content: "\f2b2"; } + +.fa-thermometer:before { + content: "\f491"; } + +.fa-thermometer-empty:before { + content: "\f2cb"; } + +.fa-thermometer-full:before { + content: "\f2c7"; } + +.fa-thermometer-half:before { + content: "\f2c9"; } + +.fa-thermometer-quarter:before { + content: "\f2ca"; } + +.fa-thermometer-three-quarters:before { + content: "\f2c8"; } + +.fa-think-peaks:before { + content: "\f731"; } + +.fa-thumbs-down:before { + content: "\f165"; } + +.fa-thumbs-up:before { + content: "\f164"; } + +.fa-thumbtack:before { + content: "\f08d"; } + +.fa-ticket-alt:before { + content: "\f3ff"; } + +.fa-times:before { + content: "\f00d"; } + +.fa-times-circle:before { + content: "\f057"; } + +.fa-tint:before { + content: "\f043"; } + +.fa-tint-slash:before { + content: "\f5c7"; } + +.fa-tired:before { + content: "\f5c8"; } + +.fa-toggle-off:before { + content: "\f204"; } + +.fa-toggle-on:before { + content: "\f205"; } + +.fa-toilet:before { + content: "\f7d8"; } + +.fa-toilet-paper:before { + content: "\f71e"; } + +.fa-toolbox:before { + content: "\f552"; } + +.fa-tools:before { + content: "\f7d9"; } + +.fa-tooth:before { + content: "\f5c9"; } + +.fa-torah:before { + content: "\f6a0"; } + +.fa-torii-gate:before { + content: "\f6a1"; } + +.fa-tractor:before { + content: "\f722"; } + +.fa-trade-federation:before { + content: "\f513"; } + +.fa-trademark:before { + content: "\f25c"; } + +.fa-traffic-light:before { + content: "\f637"; } + +.fa-trailer:before { + content: "\f941"; } + +.fa-train:before { + content: "\f238"; } + +.fa-tram:before { + content: "\f7da"; } + +.fa-transgender:before { + content: "\f224"; } + +.fa-transgender-alt:before { + content: "\f225"; } + +.fa-trash:before { + content: "\f1f8"; } + +.fa-trash-alt:before { + content: "\f2ed"; } + +.fa-trash-restore:before { + content: "\f829"; } + +.fa-trash-restore-alt:before { + content: "\f82a"; } + +.fa-tree:before { + content: "\f1bb"; } + +.fa-trello:before { + content: "\f181"; } + +.fa-tripadvisor:before { + content: "\f262"; } + +.fa-trophy:before { + content: "\f091"; } + +.fa-truck:before { + content: "\f0d1"; } + +.fa-truck-loading:before { + content: "\f4de"; } + +.fa-truck-monster:before { + content: "\f63b"; } + +.fa-truck-moving:before { + content: "\f4df"; } + +.fa-truck-pickup:before { + content: "\f63c"; } + +.fa-tshirt:before { + content: "\f553"; } + +.fa-tty:before { + content: "\f1e4"; } + +.fa-tumblr:before { + content: "\f173"; } + +.fa-tumblr-square:before { + content: "\f174"; } + +.fa-tv:before { + content: "\f26c"; } + +.fa-twitch:before { + content: "\f1e8"; } + +.fa-twitter:before { + content: "\f099"; } + +.fa-twitter-square:before { + content: "\f081"; } + +.fa-typo3:before { + content: "\f42b"; } + +.fa-uber:before { + content: "\f402"; } + +.fa-ubuntu:before { + content: "\f7df"; } + +.fa-uikit:before { + content: "\f403"; } + +.fa-umbraco:before { + content: "\f8e8"; } + +.fa-umbrella:before { + content: "\f0e9"; } + +.fa-umbrella-beach:before { + content: "\f5ca"; } + +.fa-underline:before { + content: "\f0cd"; } + +.fa-undo:before { + content: "\f0e2"; } + +.fa-undo-alt:before { + content: "\f2ea"; } + +.fa-uniregistry:before { + content: "\f404"; } + +.fa-unity:before { + content: "\f949"; } + +.fa-universal-access:before { + content: "\f29a"; } + +.fa-university:before { + content: "\f19c"; } + +.fa-unlink:before { + content: "\f127"; } + +.fa-unlock:before { + content: "\f09c"; } + +.fa-unlock-alt:before { + content: "\f13e"; } + +.fa-untappd:before { + content: "\f405"; } + +.fa-upload:before { + content: "\f093"; } + +.fa-ups:before { + content: "\f7e0"; } + +.fa-usb:before { + content: "\f287"; } + +.fa-user:before { + content: "\f007"; } + +.fa-user-alt:before { + content: "\f406"; } + +.fa-user-alt-slash:before { + content: "\f4fa"; } + +.fa-user-astronaut:before { + content: "\f4fb"; } + +.fa-user-check:before { + content: "\f4fc"; } + +.fa-user-circle:before { + content: "\f2bd"; } + +.fa-user-clock:before { + content: "\f4fd"; } + +.fa-user-cog:before { + content: "\f4fe"; } + +.fa-user-edit:before { + content: "\f4ff"; } + +.fa-user-friends:before { + content: "\f500"; } + +.fa-user-graduate:before { + content: "\f501"; } + +.fa-user-injured:before { + content: "\f728"; } + +.fa-user-lock:before { + content: "\f502"; } + +.fa-user-md:before { + content: "\f0f0"; } + +.fa-user-minus:before { + content: "\f503"; } + +.fa-user-ninja:before { + content: "\f504"; } + +.fa-user-nurse:before { + content: "\f82f"; } + +.fa-user-plus:before { + content: "\f234"; } + +.fa-user-secret:before { + content: "\f21b"; } + +.fa-user-shield:before { + content: "\f505"; } + +.fa-user-slash:before { + content: "\f506"; } + +.fa-user-tag:before { + content: "\f507"; } + +.fa-user-tie:before { + content: "\f508"; } + +.fa-user-times:before { + content: "\f235"; } + +.fa-users:before { + content: "\f0c0"; } + +.fa-users-cog:before { + content: "\f509"; } + +.fa-usps:before { + content: "\f7e1"; } + +.fa-ussunnah:before { + content: "\f407"; } + +.fa-utensil-spoon:before { + content: "\f2e5"; } + +.fa-utensils:before { + content: "\f2e7"; } + +.fa-vaadin:before { + content: "\f408"; } + +.fa-vector-square:before { + content: "\f5cb"; } + +.fa-venus:before { + content: "\f221"; } + +.fa-venus-double:before { + content: "\f226"; } + +.fa-venus-mars:before { + content: "\f228"; } + +.fa-viacoin:before { + content: "\f237"; } + +.fa-viadeo:before { + content: "\f2a9"; } + +.fa-viadeo-square:before { + content: "\f2aa"; } + +.fa-vial:before { + content: "\f492"; } + +.fa-vials:before { + content: "\f493"; } + +.fa-viber:before { + content: "\f409"; } + +.fa-video:before { + content: "\f03d"; } + +.fa-video-slash:before { + content: "\f4e2"; } + +.fa-vihara:before { + content: "\f6a7"; } + +.fa-vimeo:before { + content: "\f40a"; } + +.fa-vimeo-square:before { + content: "\f194"; } + +.fa-vimeo-v:before { + content: "\f27d"; } + +.fa-vine:before { + content: "\f1ca"; } + +.fa-vk:before { + content: "\f189"; } + +.fa-vnv:before { + content: "\f40b"; } + +.fa-voicemail:before { + content: "\f897"; } + +.fa-volleyball-ball:before { + content: "\f45f"; } + +.fa-volume-down:before { + content: "\f027"; } + +.fa-volume-mute:before { + content: "\f6a9"; } + +.fa-volume-off:before { + content: "\f026"; } + +.fa-volume-up:before { + content: "\f028"; } + +.fa-vote-yea:before { + content: "\f772"; } + +.fa-vr-cardboard:before { + content: "\f729"; } + +.fa-vuejs:before { + content: "\f41f"; } + +.fa-walking:before { + content: "\f554"; } + +.fa-wallet:before { + content: "\f555"; } + +.fa-warehouse:before { + content: "\f494"; } + +.fa-water:before { + content: "\f773"; } + +.fa-wave-square:before { + content: "\f83e"; } + +.fa-waze:before { + content: "\f83f"; } + +.fa-weebly:before { + content: "\f5cc"; } + +.fa-weibo:before { + content: "\f18a"; } + +.fa-weight:before { + content: "\f496"; } + +.fa-weight-hanging:before { + content: "\f5cd"; } + +.fa-weixin:before { + content: "\f1d7"; } + +.fa-whatsapp:before { + content: "\f232"; } + +.fa-whatsapp-square:before { + content: "\f40c"; } + +.fa-wheelchair:before { + content: "\f193"; } + +.fa-whmcs:before { + content: "\f40d"; } + +.fa-wifi:before { + content: "\f1eb"; } + +.fa-wikipedia-w:before { + content: "\f266"; } + +.fa-wind:before { + content: "\f72e"; } + +.fa-window-close:before { + content: "\f410"; } + +.fa-window-maximize:before { + content: "\f2d0"; } + +.fa-window-minimize:before { + content: "\f2d1"; } + +.fa-window-restore:before { + content: "\f2d2"; } + +.fa-windows:before { + content: "\f17a"; } + +.fa-wine-bottle:before { + content: "\f72f"; } + +.fa-wine-glass:before { + content: "\f4e3"; } + +.fa-wine-glass-alt:before { + content: "\f5ce"; } + +.fa-wix:before { + content: "\f5cf"; } + +.fa-wizards-of-the-coast:before { + content: "\f730"; } + +.fa-wolf-pack-battalion:before { + content: "\f514"; } + +.fa-won-sign:before { + content: "\f159"; } + +.fa-wordpress:before { + content: "\f19a"; } + +.fa-wordpress-simple:before { + content: "\f411"; } + +.fa-wpbeginner:before { + content: "\f297"; } + +.fa-wpexplorer:before { + content: "\f2de"; } + +.fa-wpforms:before { + content: "\f298"; } + +.fa-wpressr:before { + content: "\f3e4"; } + +.fa-wrench:before { + content: "\f0ad"; } + +.fa-x-ray:before { + content: "\f497"; } + +.fa-xbox:before { + content: "\f412"; } + +.fa-xing:before { + content: "\f168"; } + +.fa-xing-square:before { + content: "\f169"; } + +.fa-y-combinator:before { + content: "\f23b"; } + +.fa-yahoo:before { + content: "\f19e"; } + +.fa-yammer:before { + content: "\f840"; } + +.fa-yandex:before { + content: "\f413"; } + +.fa-yandex-international:before { + content: "\f414"; } + +.fa-yarn:before { + content: "\f7e3"; } + +.fa-yelp:before { + content: "\f1e9"; } + +.fa-yen-sign:before { + content: "\f157"; } + +.fa-yin-yang:before { + content: "\f6ad"; } + +.fa-yoast:before { + content: "\f2b1"; } + +.fa-youtube:before { + content: "\f167"; } + +.fa-youtube-square:before { + content: "\f431"; } + +.fa-zhihu:before { + content: "\f63f"; } + +.sr-only { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + +.sr-only-focusable:active, .sr-only-focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; } +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-style: normal; + font-weight: normal; + font-display: auto; + src: url("../webfonts/fa-brands-400.eot"); + src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); } + +.fab { + font-family: 'Font Awesome 5 Brands'; } +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 400; + font-display: auto; + src: url("../webfonts/fa-regular-400.eot"); + src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); } + +.far { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 900; + font-display: auto; + src: url("../webfonts/fa-solid-900.eot"); + src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } + +.fa, +.fas { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/all.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/all.min.css new file mode 100644 index 00000000..1ea1b181 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/all.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\f907"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\f913"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\f91a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\f91e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\f941"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\f949"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/brands.css b/templates/map/client/libs/fontawesome/5.12.0/css/brands.css new file mode 100644 index 00000000..46b879ef --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/brands.css @@ -0,0 +1,14 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-style: normal; + font-weight: normal; + font-display: auto; + src: url("../webfonts/fa-brands-400.eot"); + src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); } + +.fab { + font-family: 'Font Awesome 5 Brands'; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/brands.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/brands.min.css new file mode 100644 index 00000000..80408195 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/brands.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/fontawesome.css b/templates/map/client/libs/fontawesome/5.12.0/css/fontawesome.css new file mode 100644 index 00000000..1327d68c --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/fontawesome.css @@ -0,0 +1,4417 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa, +.fas, +.far, +.fal, +.fad, +.fab { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; } + +.fa-lg { + font-size: 1.33333em; + line-height: 0.75em; + vertical-align: -.0667em; } + +.fa-xs { + font-size: .75em; } + +.fa-sm { + font-size: .875em; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: 2.5em; + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: -2em; + position: absolute; + text-align: center; + width: 2em; + line-height: inherit; } + +.fa-border { + border: solid 0.08em #eee; + border-radius: .1em; + padding: .2em .25em .15em; } + +.fa-pull-left { + float: left; } + +.fa-pull-right { + float: right; } + +.fa.fa-pull-left, +.fas.fa-pull-left, +.far.fa-pull-left, +.fal.fa-pull-left, +.fab.fa-pull-left { + margin-right: .3em; } + +.fa.fa-pull-right, +.fas.fa-pull-right, +.far.fa-pull-right, +.fal.fa-pull-right, +.fab.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(360deg); + transform: rotate(360deg); } } + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); } + +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-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); + transform: scale(1, -1); } + +.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-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, +:root .fa-flip-both { + -webkit-filter: none; + filter: none; } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: #fff; } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ +.fa-500px:before { + content: "\f26e"; } + +.fa-accessible-icon:before { + content: "\f368"; } + +.fa-accusoft:before { + content: "\f369"; } + +.fa-acquisitions-incorporated:before { + content: "\f6af"; } + +.fa-ad:before { + content: "\f641"; } + +.fa-address-book:before { + content: "\f2b9"; } + +.fa-address-card:before { + content: "\f2bb"; } + +.fa-adjust:before { + content: "\f042"; } + +.fa-adn:before { + content: "\f170"; } + +.fa-adobe:before { + content: "\f778"; } + +.fa-adversal:before { + content: "\f36a"; } + +.fa-affiliatetheme:before { + content: "\f36b"; } + +.fa-air-freshener:before { + content: "\f5d0"; } + +.fa-airbnb:before { + content: "\f834"; } + +.fa-algolia:before { + content: "\f36c"; } + +.fa-align-center:before { + content: "\f037"; } + +.fa-align-justify:before { + content: "\f039"; } + +.fa-align-left:before { + content: "\f036"; } + +.fa-align-right:before { + content: "\f038"; } + +.fa-alipay:before { + content: "\f642"; } + +.fa-allergies:before { + content: "\f461"; } + +.fa-amazon:before { + content: "\f270"; } + +.fa-amazon-pay:before { + content: "\f42c"; } + +.fa-ambulance:before { + content: "\f0f9"; } + +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; } + +.fa-amilia:before { + content: "\f36d"; } + +.fa-anchor:before { + content: "\f13d"; } + +.fa-android:before { + content: "\f17b"; } + +.fa-angellist:before { + content: "\f209"; } + +.fa-angle-double-down:before { + content: "\f103"; } + +.fa-angle-double-left:before { + content: "\f100"; } + +.fa-angle-double-right:before { + content: "\f101"; } + +.fa-angle-double-up:before { + content: "\f102"; } + +.fa-angle-down:before { + content: "\f107"; } + +.fa-angle-left:before { + content: "\f104"; } + +.fa-angle-right:before { + content: "\f105"; } + +.fa-angle-up:before { + content: "\f106"; } + +.fa-angry:before { + content: "\f556"; } + +.fa-angrycreative:before { + content: "\f36e"; } + +.fa-angular:before { + content: "\f420"; } + +.fa-ankh:before { + content: "\f644"; } + +.fa-app-store:before { + content: "\f36f"; } + +.fa-app-store-ios:before { + content: "\f370"; } + +.fa-apper:before { + content: "\f371"; } + +.fa-apple:before { + content: "\f179"; } + +.fa-apple-alt:before { + content: "\f5d1"; } + +.fa-apple-pay:before { + content: "\f415"; } + +.fa-archive:before { + content: "\f187"; } + +.fa-archway:before { + content: "\f557"; } + +.fa-arrow-alt-circle-down:before { + content: "\f358"; } + +.fa-arrow-alt-circle-left:before { + content: "\f359"; } + +.fa-arrow-alt-circle-right:before { + content: "\f35a"; } + +.fa-arrow-alt-circle-up:before { + content: "\f35b"; } + +.fa-arrow-circle-down:before { + content: "\f0ab"; } + +.fa-arrow-circle-left:before { + content: "\f0a8"; } + +.fa-arrow-circle-right:before { + content: "\f0a9"; } + +.fa-arrow-circle-up:before { + content: "\f0aa"; } + +.fa-arrow-down:before { + content: "\f063"; } + +.fa-arrow-left:before { + content: "\f060"; } + +.fa-arrow-right:before { + content: "\f061"; } + +.fa-arrow-up:before { + content: "\f062"; } + +.fa-arrows-alt:before { + content: "\f0b2"; } + +.fa-arrows-alt-h:before { + content: "\f337"; } + +.fa-arrows-alt-v:before { + content: "\f338"; } + +.fa-artstation:before { + content: "\f77a"; } + +.fa-assistive-listening-systems:before { + content: "\f2a2"; } + +.fa-asterisk:before { + content: "\f069"; } + +.fa-asymmetrik:before { + content: "\f372"; } + +.fa-at:before { + content: "\f1fa"; } + +.fa-atlas:before { + content: "\f558"; } + +.fa-atlassian:before { + content: "\f77b"; } + +.fa-atom:before { + content: "\f5d2"; } + +.fa-audible:before { + content: "\f373"; } + +.fa-audio-description:before { + content: "\f29e"; } + +.fa-autoprefixer:before { + content: "\f41c"; } + +.fa-avianex:before { + content: "\f374"; } + +.fa-aviato:before { + content: "\f421"; } + +.fa-award:before { + content: "\f559"; } + +.fa-aws:before { + content: "\f375"; } + +.fa-baby:before { + content: "\f77c"; } + +.fa-baby-carriage:before { + content: "\f77d"; } + +.fa-backspace:before { + content: "\f55a"; } + +.fa-backward:before { + content: "\f04a"; } + +.fa-bacon:before { + content: "\f7e5"; } + +.fa-bahai:before { + content: "\f666"; } + +.fa-balance-scale:before { + content: "\f24e"; } + +.fa-balance-scale-left:before { + content: "\f515"; } + +.fa-balance-scale-right:before { + content: "\f516"; } + +.fa-ban:before { + content: "\f05e"; } + +.fa-band-aid:before { + content: "\f462"; } + +.fa-bandcamp:before { + content: "\f2d5"; } + +.fa-barcode:before { + content: "\f02a"; } + +.fa-bars:before { + content: "\f0c9"; } + +.fa-baseball-ball:before { + content: "\f433"; } + +.fa-basketball-ball:before { + content: "\f434"; } + +.fa-bath:before { + content: "\f2cd"; } + +.fa-battery-empty:before { + content: "\f244"; } + +.fa-battery-full:before { + content: "\f240"; } + +.fa-battery-half:before { + content: "\f242"; } + +.fa-battery-quarter:before { + content: "\f243"; } + +.fa-battery-three-quarters:before { + content: "\f241"; } + +.fa-battle-net:before { + content: "\f835"; } + +.fa-bed:before { + content: "\f236"; } + +.fa-beer:before { + content: "\f0fc"; } + +.fa-behance:before { + content: "\f1b4"; } + +.fa-behance-square:before { + content: "\f1b5"; } + +.fa-bell:before { + content: "\f0f3"; } + +.fa-bell-slash:before { + content: "\f1f6"; } + +.fa-bezier-curve:before { + content: "\f55b"; } + +.fa-bible:before { + content: "\f647"; } + +.fa-bicycle:before { + content: "\f206"; } + +.fa-biking:before { + content: "\f84a"; } + +.fa-bimobject:before { + content: "\f378"; } + +.fa-binoculars:before { + content: "\f1e5"; } + +.fa-biohazard:before { + content: "\f780"; } + +.fa-birthday-cake:before { + content: "\f1fd"; } + +.fa-bitbucket:before { + content: "\f171"; } + +.fa-bitcoin:before { + content: "\f379"; } + +.fa-bity:before { + content: "\f37a"; } + +.fa-black-tie:before { + content: "\f27e"; } + +.fa-blackberry:before { + content: "\f37b"; } + +.fa-blender:before { + content: "\f517"; } + +.fa-blender-phone:before { + content: "\f6b6"; } + +.fa-blind:before { + content: "\f29d"; } + +.fa-blog:before { + content: "\f781"; } + +.fa-blogger:before { + content: "\f37c"; } + +.fa-blogger-b:before { + content: "\f37d"; } + +.fa-bluetooth:before { + content: "\f293"; } + +.fa-bluetooth-b:before { + content: "\f294"; } + +.fa-bold:before { + content: "\f032"; } + +.fa-bolt:before { + content: "\f0e7"; } + +.fa-bomb:before { + content: "\f1e2"; } + +.fa-bone:before { + content: "\f5d7"; } + +.fa-bong:before { + content: "\f55c"; } + +.fa-book:before { + content: "\f02d"; } + +.fa-book-dead:before { + content: "\f6b7"; } + +.fa-book-medical:before { + content: "\f7e6"; } + +.fa-book-open:before { + content: "\f518"; } + +.fa-book-reader:before { + content: "\f5da"; } + +.fa-bookmark:before { + content: "\f02e"; } + +.fa-bootstrap:before { + content: "\f836"; } + +.fa-border-all:before { + content: "\f84c"; } + +.fa-border-none:before { + content: "\f850"; } + +.fa-border-style:before { + content: "\f853"; } + +.fa-bowling-ball:before { + content: "\f436"; } + +.fa-box:before { + content: "\f466"; } + +.fa-box-open:before { + content: "\f49e"; } + +.fa-boxes:before { + content: "\f468"; } + +.fa-braille:before { + content: "\f2a1"; } + +.fa-brain:before { + content: "\f5dc"; } + +.fa-bread-slice:before { + content: "\f7ec"; } + +.fa-briefcase:before { + content: "\f0b1"; } + +.fa-briefcase-medical:before { + content: "\f469"; } + +.fa-broadcast-tower:before { + content: "\f519"; } + +.fa-broom:before { + content: "\f51a"; } + +.fa-brush:before { + content: "\f55d"; } + +.fa-btc:before { + content: "\f15a"; } + +.fa-buffer:before { + content: "\f837"; } + +.fa-bug:before { + content: "\f188"; } + +.fa-building:before { + content: "\f1ad"; } + +.fa-bullhorn:before { + content: "\f0a1"; } + +.fa-bullseye:before { + content: "\f140"; } + +.fa-burn:before { + content: "\f46a"; } + +.fa-buromobelexperte:before { + content: "\f37f"; } + +.fa-bus:before { + content: "\f207"; } + +.fa-bus-alt:before { + content: "\f55e"; } + +.fa-business-time:before { + content: "\f64a"; } + +.fa-buy-n-large:before { + content: "\f8a6"; } + +.fa-buysellads:before { + content: "\f20d"; } + +.fa-calculator:before { + content: "\f1ec"; } + +.fa-calendar:before { + content: "\f133"; } + +.fa-calendar-alt:before { + content: "\f073"; } + +.fa-calendar-check:before { + content: "\f274"; } + +.fa-calendar-day:before { + content: "\f783"; } + +.fa-calendar-minus:before { + content: "\f272"; } + +.fa-calendar-plus:before { + content: "\f271"; } + +.fa-calendar-times:before { + content: "\f273"; } + +.fa-calendar-week:before { + content: "\f784"; } + +.fa-camera:before { + content: "\f030"; } + +.fa-camera-retro:before { + content: "\f083"; } + +.fa-campground:before { + content: "\f6bb"; } + +.fa-canadian-maple-leaf:before { + content: "\f785"; } + +.fa-candy-cane:before { + content: "\f786"; } + +.fa-cannabis:before { + content: "\f55f"; } + +.fa-capsules:before { + content: "\f46b"; } + +.fa-car:before { + content: "\f1b9"; } + +.fa-car-alt:before { + content: "\f5de"; } + +.fa-car-battery:before { + content: "\f5df"; } + +.fa-car-crash:before { + content: "\f5e1"; } + +.fa-car-side:before { + content: "\f5e4"; } + +.fa-caravan:before { + content: "\f8ff"; } + +.fa-caret-down:before { + content: "\f0d7"; } + +.fa-caret-left:before { + content: "\f0d9"; } + +.fa-caret-right:before { + content: "\f0da"; } + +.fa-caret-square-down:before { + content: "\f150"; } + +.fa-caret-square-left:before { + content: "\f191"; } + +.fa-caret-square-right:before { + content: "\f152"; } + +.fa-caret-square-up:before { + content: "\f151"; } + +.fa-caret-up:before { + content: "\f0d8"; } + +.fa-carrot:before { + content: "\f787"; } + +.fa-cart-arrow-down:before { + content: "\f218"; } + +.fa-cart-plus:before { + content: "\f217"; } + +.fa-cash-register:before { + content: "\f788"; } + +.fa-cat:before { + content: "\f6be"; } + +.fa-cc-amazon-pay:before { + content: "\f42d"; } + +.fa-cc-amex:before { + content: "\f1f3"; } + +.fa-cc-apple-pay:before { + content: "\f416"; } + +.fa-cc-diners-club:before { + content: "\f24c"; } + +.fa-cc-discover:before { + content: "\f1f2"; } + +.fa-cc-jcb:before { + content: "\f24b"; } + +.fa-cc-mastercard:before { + content: "\f1f1"; } + +.fa-cc-paypal:before { + content: "\f1f4"; } + +.fa-cc-stripe:before { + content: "\f1f5"; } + +.fa-cc-visa:before { + content: "\f1f0"; } + +.fa-centercode:before { + content: "\f380"; } + +.fa-centos:before { + content: "\f789"; } + +.fa-certificate:before { + content: "\f0a3"; } + +.fa-chair:before { + content: "\f6c0"; } + +.fa-chalkboard:before { + content: "\f51b"; } + +.fa-chalkboard-teacher:before { + content: "\f51c"; } + +.fa-charging-station:before { + content: "\f5e7"; } + +.fa-chart-area:before { + content: "\f1fe"; } + +.fa-chart-bar:before { + content: "\f080"; } + +.fa-chart-line:before { + content: "\f201"; } + +.fa-chart-pie:before { + content: "\f200"; } + +.fa-check:before { + content: "\f00c"; } + +.fa-check-circle:before { + content: "\f058"; } + +.fa-check-double:before { + content: "\f560"; } + +.fa-check-square:before { + content: "\f14a"; } + +.fa-cheese:before { + content: "\f7ef"; } + +.fa-chess:before { + content: "\f439"; } + +.fa-chess-bishop:before { + content: "\f43a"; } + +.fa-chess-board:before { + content: "\f43c"; } + +.fa-chess-king:before { + content: "\f43f"; } + +.fa-chess-knight:before { + content: "\f441"; } + +.fa-chess-pawn:before { + content: "\f443"; } + +.fa-chess-queen:before { + content: "\f445"; } + +.fa-chess-rook:before { + content: "\f447"; } + +.fa-chevron-circle-down:before { + content: "\f13a"; } + +.fa-chevron-circle-left:before { + content: "\f137"; } + +.fa-chevron-circle-right:before { + content: "\f138"; } + +.fa-chevron-circle-up:before { + content: "\f139"; } + +.fa-chevron-down:before { + content: "\f078"; } + +.fa-chevron-left:before { + content: "\f053"; } + +.fa-chevron-right:before { + content: "\f054"; } + +.fa-chevron-up:before { + content: "\f077"; } + +.fa-child:before { + content: "\f1ae"; } + +.fa-chrome:before { + content: "\f268"; } + +.fa-chromecast:before { + content: "\f838"; } + +.fa-church:before { + content: "\f51d"; } + +.fa-circle:before { + content: "\f111"; } + +.fa-circle-notch:before { + content: "\f1ce"; } + +.fa-city:before { + content: "\f64f"; } + +.fa-clinic-medical:before { + content: "\f7f2"; } + +.fa-clipboard:before { + content: "\f328"; } + +.fa-clipboard-check:before { + content: "\f46c"; } + +.fa-clipboard-list:before { + content: "\f46d"; } + +.fa-clock:before { + content: "\f017"; } + +.fa-clone:before { + content: "\f24d"; } + +.fa-closed-captioning:before { + content: "\f20a"; } + +.fa-cloud:before { + content: "\f0c2"; } + +.fa-cloud-download-alt:before { + content: "\f381"; } + +.fa-cloud-meatball:before { + content: "\f73b"; } + +.fa-cloud-moon:before { + content: "\f6c3"; } + +.fa-cloud-moon-rain:before { + content: "\f73c"; } + +.fa-cloud-rain:before { + content: "\f73d"; } + +.fa-cloud-showers-heavy:before { + content: "\f740"; } + +.fa-cloud-sun:before { + content: "\f6c4"; } + +.fa-cloud-sun-rain:before { + content: "\f743"; } + +.fa-cloud-upload-alt:before { + content: "\f382"; } + +.fa-cloudscale:before { + content: "\f383"; } + +.fa-cloudsmith:before { + content: "\f384"; } + +.fa-cloudversify:before { + content: "\f385"; } + +.fa-cocktail:before { + content: "\f561"; } + +.fa-code:before { + content: "\f121"; } + +.fa-code-branch:before { + content: "\f126"; } + +.fa-codepen:before { + content: "\f1cb"; } + +.fa-codiepie:before { + content: "\f284"; } + +.fa-coffee:before { + content: "\f0f4"; } + +.fa-cog:before { + content: "\f013"; } + +.fa-cogs:before { + content: "\f085"; } + +.fa-coins:before { + content: "\f51e"; } + +.fa-columns:before { + content: "\f0db"; } + +.fa-comment:before { + content: "\f075"; } + +.fa-comment-alt:before { + content: "\f27a"; } + +.fa-comment-dollar:before { + content: "\f651"; } + +.fa-comment-dots:before { + content: "\f4ad"; } + +.fa-comment-medical:before { + content: "\f7f5"; } + +.fa-comment-slash:before { + content: "\f4b3"; } + +.fa-comments:before { + content: "\f086"; } + +.fa-comments-dollar:before { + content: "\f653"; } + +.fa-compact-disc:before { + content: "\f51f"; } + +.fa-compass:before { + content: "\f14e"; } + +.fa-compress:before { + content: "\f066"; } + +.fa-compress-alt:before { + content: "\f422"; } + +.fa-compress-arrows-alt:before { + content: "\f78c"; } + +.fa-concierge-bell:before { + content: "\f562"; } + +.fa-confluence:before { + content: "\f78d"; } + +.fa-connectdevelop:before { + content: "\f20e"; } + +.fa-contao:before { + content: "\f26d"; } + +.fa-cookie:before { + content: "\f563"; } + +.fa-cookie-bite:before { + content: "\f564"; } + +.fa-copy:before { + content: "\f0c5"; } + +.fa-copyright:before { + content: "\f1f9"; } + +.fa-cotton-bureau:before { + content: "\f89e"; } + +.fa-couch:before { + content: "\f4b8"; } + +.fa-cpanel:before { + content: "\f388"; } + +.fa-creative-commons:before { + content: "\f25e"; } + +.fa-creative-commons-by:before { + content: "\f4e7"; } + +.fa-creative-commons-nc:before { + content: "\f4e8"; } + +.fa-creative-commons-nc-eu:before { + content: "\f4e9"; } + +.fa-creative-commons-nc-jp:before { + content: "\f4ea"; } + +.fa-creative-commons-nd:before { + content: "\f4eb"; } + +.fa-creative-commons-pd:before { + content: "\f4ec"; } + +.fa-creative-commons-pd-alt:before { + content: "\f4ed"; } + +.fa-creative-commons-remix:before { + content: "\f4ee"; } + +.fa-creative-commons-sa:before { + content: "\f4ef"; } + +.fa-creative-commons-sampling:before { + content: "\f4f0"; } + +.fa-creative-commons-sampling-plus:before { + content: "\f4f1"; } + +.fa-creative-commons-share:before { + content: "\f4f2"; } + +.fa-creative-commons-zero:before { + content: "\f4f3"; } + +.fa-credit-card:before { + content: "\f09d"; } + +.fa-critical-role:before { + content: "\f6c9"; } + +.fa-crop:before { + content: "\f125"; } + +.fa-crop-alt:before { + content: "\f565"; } + +.fa-cross:before { + content: "\f654"; } + +.fa-crosshairs:before { + content: "\f05b"; } + +.fa-crow:before { + content: "\f520"; } + +.fa-crown:before { + content: "\f521"; } + +.fa-crutch:before { + content: "\f7f7"; } + +.fa-css3:before { + content: "\f13c"; } + +.fa-css3-alt:before { + content: "\f38b"; } + +.fa-cube:before { + content: "\f1b2"; } + +.fa-cubes:before { + content: "\f1b3"; } + +.fa-cut:before { + content: "\f0c4"; } + +.fa-cuttlefish:before { + content: "\f38c"; } + +.fa-d-and-d:before { + content: "\f38d"; } + +.fa-d-and-d-beyond:before { + content: "\f6ca"; } + +.fa-dashcube:before { + content: "\f210"; } + +.fa-database:before { + content: "\f1c0"; } + +.fa-deaf:before { + content: "\f2a4"; } + +.fa-delicious:before { + content: "\f1a5"; } + +.fa-democrat:before { + content: "\f747"; } + +.fa-deploydog:before { + content: "\f38e"; } + +.fa-deskpro:before { + content: "\f38f"; } + +.fa-desktop:before { + content: "\f108"; } + +.fa-dev:before { + content: "\f6cc"; } + +.fa-deviantart:before { + content: "\f1bd"; } + +.fa-dharmachakra:before { + content: "\f655"; } + +.fa-dhl:before { + content: "\f790"; } + +.fa-diagnoses:before { + content: "\f470"; } + +.fa-diaspora:before { + content: "\f791"; } + +.fa-dice:before { + content: "\f522"; } + +.fa-dice-d20:before { + content: "\f6cf"; } + +.fa-dice-d6:before { + content: "\f6d1"; } + +.fa-dice-five:before { + content: "\f523"; } + +.fa-dice-four:before { + content: "\f524"; } + +.fa-dice-one:before { + content: "\f525"; } + +.fa-dice-six:before { + content: "\f526"; } + +.fa-dice-three:before { + content: "\f527"; } + +.fa-dice-two:before { + content: "\f528"; } + +.fa-digg:before { + content: "\f1a6"; } + +.fa-digital-ocean:before { + content: "\f391"; } + +.fa-digital-tachograph:before { + content: "\f566"; } + +.fa-directions:before { + content: "\f5eb"; } + +.fa-discord:before { + content: "\f392"; } + +.fa-discourse:before { + content: "\f393"; } + +.fa-divide:before { + content: "\f529"; } + +.fa-dizzy:before { + content: "\f567"; } + +.fa-dna:before { + content: "\f471"; } + +.fa-dochub:before { + content: "\f394"; } + +.fa-docker:before { + content: "\f395"; } + +.fa-dog:before { + content: "\f6d3"; } + +.fa-dollar-sign:before { + content: "\f155"; } + +.fa-dolly:before { + content: "\f472"; } + +.fa-dolly-flatbed:before { + content: "\f474"; } + +.fa-donate:before { + content: "\f4b9"; } + +.fa-door-closed:before { + content: "\f52a"; } + +.fa-door-open:before { + content: "\f52b"; } + +.fa-dot-circle:before { + content: "\f192"; } + +.fa-dove:before { + content: "\f4ba"; } + +.fa-download:before { + content: "\f019"; } + +.fa-draft2digital:before { + content: "\f396"; } + +.fa-drafting-compass:before { + content: "\f568"; } + +.fa-dragon:before { + content: "\f6d5"; } + +.fa-draw-polygon:before { + content: "\f5ee"; } + +.fa-dribbble:before { + content: "\f17d"; } + +.fa-dribbble-square:before { + content: "\f397"; } + +.fa-dropbox:before { + content: "\f16b"; } + +.fa-drum:before { + content: "\f569"; } + +.fa-drum-steelpan:before { + content: "\f56a"; } + +.fa-drumstick-bite:before { + content: "\f6d7"; } + +.fa-drupal:before { + content: "\f1a9"; } + +.fa-dumbbell:before { + content: "\f44b"; } + +.fa-dumpster:before { + content: "\f793"; } + +.fa-dumpster-fire:before { + content: "\f794"; } + +.fa-dungeon:before { + content: "\f6d9"; } + +.fa-dyalog:before { + content: "\f399"; } + +.fa-earlybirds:before { + content: "\f39a"; } + +.fa-ebay:before { + content: "\f4f4"; } + +.fa-edge:before { + content: "\f282"; } + +.fa-edit:before { + content: "\f044"; } + +.fa-egg:before { + content: "\f7fb"; } + +.fa-eject:before { + content: "\f052"; } + +.fa-elementor:before { + content: "\f430"; } + +.fa-ellipsis-h:before { + content: "\f141"; } + +.fa-ellipsis-v:before { + content: "\f142"; } + +.fa-ello:before { + content: "\f5f1"; } + +.fa-ember:before { + content: "\f423"; } + +.fa-empire:before { + content: "\f1d1"; } + +.fa-envelope:before { + content: "\f0e0"; } + +.fa-envelope-open:before { + content: "\f2b6"; } + +.fa-envelope-open-text:before { + content: "\f658"; } + +.fa-envelope-square:before { + content: "\f199"; } + +.fa-envira:before { + content: "\f299"; } + +.fa-equals:before { + content: "\f52c"; } + +.fa-eraser:before { + content: "\f12d"; } + +.fa-erlang:before { + content: "\f39d"; } + +.fa-ethereum:before { + content: "\f42e"; } + +.fa-ethernet:before { + content: "\f796"; } + +.fa-etsy:before { + content: "\f2d7"; } + +.fa-euro-sign:before { + content: "\f153"; } + +.fa-evernote:before { + content: "\f839"; } + +.fa-exchange-alt:before { + content: "\f362"; } + +.fa-exclamation:before { + content: "\f12a"; } + +.fa-exclamation-circle:before { + content: "\f06a"; } + +.fa-exclamation-triangle:before { + content: "\f071"; } + +.fa-expand:before { + content: "\f065"; } + +.fa-expand-alt:before { + content: "\f424"; } + +.fa-expand-arrows-alt:before { + content: "\f31e"; } + +.fa-expeditedssl:before { + content: "\f23e"; } + +.fa-external-link-alt:before { + content: "\f35d"; } + +.fa-external-link-square-alt:before { + content: "\f360"; } + +.fa-eye:before { + content: "\f06e"; } + +.fa-eye-dropper:before { + content: "\f1fb"; } + +.fa-eye-slash:before { + content: "\f070"; } + +.fa-facebook:before { + content: "\f09a"; } + +.fa-facebook-f:before { + content: "\f39e"; } + +.fa-facebook-messenger:before { + content: "\f39f"; } + +.fa-facebook-square:before { + content: "\f082"; } + +.fa-fan:before { + content: "\f863"; } + +.fa-fantasy-flight-games:before { + content: "\f6dc"; } + +.fa-fast-backward:before { + content: "\f049"; } + +.fa-fast-forward:before { + content: "\f050"; } + +.fa-fax:before { + content: "\f1ac"; } + +.fa-feather:before { + content: "\f52d"; } + +.fa-feather-alt:before { + content: "\f56b"; } + +.fa-fedex:before { + content: "\f797"; } + +.fa-fedora:before { + content: "\f798"; } + +.fa-female:before { + content: "\f182"; } + +.fa-fighter-jet:before { + content: "\f0fb"; } + +.fa-figma:before { + content: "\f799"; } + +.fa-file:before { + content: "\f15b"; } + +.fa-file-alt:before { + content: "\f15c"; } + +.fa-file-archive:before { + content: "\f1c6"; } + +.fa-file-audio:before { + content: "\f1c7"; } + +.fa-file-code:before { + content: "\f1c9"; } + +.fa-file-contract:before { + content: "\f56c"; } + +.fa-file-csv:before { + content: "\f6dd"; } + +.fa-file-download:before { + content: "\f56d"; } + +.fa-file-excel:before { + content: "\f1c3"; } + +.fa-file-export:before { + content: "\f56e"; } + +.fa-file-image:before { + content: "\f1c5"; } + +.fa-file-import:before { + content: "\f56f"; } + +.fa-file-invoice:before { + content: "\f570"; } + +.fa-file-invoice-dollar:before { + content: "\f571"; } + +.fa-file-medical:before { + content: "\f477"; } + +.fa-file-medical-alt:before { + content: "\f478"; } + +.fa-file-pdf:before { + content: "\f1c1"; } + +.fa-file-powerpoint:before { + content: "\f1c4"; } + +.fa-file-prescription:before { + content: "\f572"; } + +.fa-file-signature:before { + content: "\f573"; } + +.fa-file-upload:before { + content: "\f574"; } + +.fa-file-video:before { + content: "\f1c8"; } + +.fa-file-word:before { + content: "\f1c2"; } + +.fa-fill:before { + content: "\f575"; } + +.fa-fill-drip:before { + content: "\f576"; } + +.fa-film:before { + content: "\f008"; } + +.fa-filter:before { + content: "\f0b0"; } + +.fa-fingerprint:before { + content: "\f577"; } + +.fa-fire:before { + content: "\f06d"; } + +.fa-fire-alt:before { + content: "\f7e4"; } + +.fa-fire-extinguisher:before { + content: "\f134"; } + +.fa-firefox:before { + content: "\f269"; } + +.fa-firefox-browser:before { + content: "\f907"; } + +.fa-first-aid:before { + content: "\f479"; } + +.fa-first-order:before { + content: "\f2b0"; } + +.fa-first-order-alt:before { + content: "\f50a"; } + +.fa-firstdraft:before { + content: "\f3a1"; } + +.fa-fish:before { + content: "\f578"; } + +.fa-fist-raised:before { + content: "\f6de"; } + +.fa-flag:before { + content: "\f024"; } + +.fa-flag-checkered:before { + content: "\f11e"; } + +.fa-flag-usa:before { + content: "\f74d"; } + +.fa-flask:before { + content: "\f0c3"; } + +.fa-flickr:before { + content: "\f16e"; } + +.fa-flipboard:before { + content: "\f44d"; } + +.fa-flushed:before { + content: "\f579"; } + +.fa-fly:before { + content: "\f417"; } + +.fa-folder:before { + content: "\f07b"; } + +.fa-folder-minus:before { + content: "\f65d"; } + +.fa-folder-open:before { + content: "\f07c"; } + +.fa-folder-plus:before { + content: "\f65e"; } + +.fa-font:before { + content: "\f031"; } + +.fa-font-awesome:before { + content: "\f2b4"; } + +.fa-font-awesome-alt:before { + content: "\f35c"; } + +.fa-font-awesome-flag:before { + content: "\f425"; } + +.fa-font-awesome-logo-full:before { + content: "\f4e6"; } + +.fa-fonticons:before { + content: "\f280"; } + +.fa-fonticons-fi:before { + content: "\f3a2"; } + +.fa-football-ball:before { + content: "\f44e"; } + +.fa-fort-awesome:before { + content: "\f286"; } + +.fa-fort-awesome-alt:before { + content: "\f3a3"; } + +.fa-forumbee:before { + content: "\f211"; } + +.fa-forward:before { + content: "\f04e"; } + +.fa-foursquare:before { + content: "\f180"; } + +.fa-free-code-camp:before { + content: "\f2c5"; } + +.fa-freebsd:before { + content: "\f3a4"; } + +.fa-frog:before { + content: "\f52e"; } + +.fa-frown:before { + content: "\f119"; } + +.fa-frown-open:before { + content: "\f57a"; } + +.fa-fulcrum:before { + content: "\f50b"; } + +.fa-funnel-dollar:before { + content: "\f662"; } + +.fa-futbol:before { + content: "\f1e3"; } + +.fa-galactic-republic:before { + content: "\f50c"; } + +.fa-galactic-senate:before { + content: "\f50d"; } + +.fa-gamepad:before { + content: "\f11b"; } + +.fa-gas-pump:before { + content: "\f52f"; } + +.fa-gavel:before { + content: "\f0e3"; } + +.fa-gem:before { + content: "\f3a5"; } + +.fa-genderless:before { + content: "\f22d"; } + +.fa-get-pocket:before { + content: "\f265"; } + +.fa-gg:before { + content: "\f260"; } + +.fa-gg-circle:before { + content: "\f261"; } + +.fa-ghost:before { + content: "\f6e2"; } + +.fa-gift:before { + content: "\f06b"; } + +.fa-gifts:before { + content: "\f79c"; } + +.fa-git:before { + content: "\f1d3"; } + +.fa-git-alt:before { + content: "\f841"; } + +.fa-git-square:before { + content: "\f1d2"; } + +.fa-github:before { + content: "\f09b"; } + +.fa-github-alt:before { + content: "\f113"; } + +.fa-github-square:before { + content: "\f092"; } + +.fa-gitkraken:before { + content: "\f3a6"; } + +.fa-gitlab:before { + content: "\f296"; } + +.fa-gitter:before { + content: "\f426"; } + +.fa-glass-cheers:before { + content: "\f79f"; } + +.fa-glass-martini:before { + content: "\f000"; } + +.fa-glass-martini-alt:before { + content: "\f57b"; } + +.fa-glass-whiskey:before { + content: "\f7a0"; } + +.fa-glasses:before { + content: "\f530"; } + +.fa-glide:before { + content: "\f2a5"; } + +.fa-glide-g:before { + content: "\f2a6"; } + +.fa-globe:before { + content: "\f0ac"; } + +.fa-globe-africa:before { + content: "\f57c"; } + +.fa-globe-americas:before { + content: "\f57d"; } + +.fa-globe-asia:before { + content: "\f57e"; } + +.fa-globe-europe:before { + content: "\f7a2"; } + +.fa-gofore:before { + content: "\f3a7"; } + +.fa-golf-ball:before { + content: "\f450"; } + +.fa-goodreads:before { + content: "\f3a8"; } + +.fa-goodreads-g:before { + content: "\f3a9"; } + +.fa-google:before { + content: "\f1a0"; } + +.fa-google-drive:before { + content: "\f3aa"; } + +.fa-google-play:before { + content: "\f3ab"; } + +.fa-google-plus:before { + content: "\f2b3"; } + +.fa-google-plus-g:before { + content: "\f0d5"; } + +.fa-google-plus-square:before { + content: "\f0d4"; } + +.fa-google-wallet:before { + content: "\f1ee"; } + +.fa-gopuram:before { + content: "\f664"; } + +.fa-graduation-cap:before { + content: "\f19d"; } + +.fa-gratipay:before { + content: "\f184"; } + +.fa-grav:before { + content: "\f2d6"; } + +.fa-greater-than:before { + content: "\f531"; } + +.fa-greater-than-equal:before { + content: "\f532"; } + +.fa-grimace:before { + content: "\f57f"; } + +.fa-grin:before { + content: "\f580"; } + +.fa-grin-alt:before { + content: "\f581"; } + +.fa-grin-beam:before { + content: "\f582"; } + +.fa-grin-beam-sweat:before { + content: "\f583"; } + +.fa-grin-hearts:before { + content: "\f584"; } + +.fa-grin-squint:before { + content: "\f585"; } + +.fa-grin-squint-tears:before { + content: "\f586"; } + +.fa-grin-stars:before { + content: "\f587"; } + +.fa-grin-tears:before { + content: "\f588"; } + +.fa-grin-tongue:before { + content: "\f589"; } + +.fa-grin-tongue-squint:before { + content: "\f58a"; } + +.fa-grin-tongue-wink:before { + content: "\f58b"; } + +.fa-grin-wink:before { + content: "\f58c"; } + +.fa-grip-horizontal:before { + content: "\f58d"; } + +.fa-grip-lines:before { + content: "\f7a4"; } + +.fa-grip-lines-vertical:before { + content: "\f7a5"; } + +.fa-grip-vertical:before { + content: "\f58e"; } + +.fa-gripfire:before { + content: "\f3ac"; } + +.fa-grunt:before { + content: "\f3ad"; } + +.fa-guitar:before { + content: "\f7a6"; } + +.fa-gulp:before { + content: "\f3ae"; } + +.fa-h-square:before { + content: "\f0fd"; } + +.fa-hacker-news:before { + content: "\f1d4"; } + +.fa-hacker-news-square:before { + content: "\f3af"; } + +.fa-hackerrank:before { + content: "\f5f7"; } + +.fa-hamburger:before { + content: "\f805"; } + +.fa-hammer:before { + content: "\f6e3"; } + +.fa-hamsa:before { + content: "\f665"; } + +.fa-hand-holding:before { + content: "\f4bd"; } + +.fa-hand-holding-heart:before { + content: "\f4be"; } + +.fa-hand-holding-usd:before { + content: "\f4c0"; } + +.fa-hand-lizard:before { + content: "\f258"; } + +.fa-hand-middle-finger:before { + content: "\f806"; } + +.fa-hand-paper:before { + content: "\f256"; } + +.fa-hand-peace:before { + content: "\f25b"; } + +.fa-hand-point-down:before { + content: "\f0a7"; } + +.fa-hand-point-left:before { + content: "\f0a5"; } + +.fa-hand-point-right:before { + content: "\f0a4"; } + +.fa-hand-point-up:before { + content: "\f0a6"; } + +.fa-hand-pointer:before { + content: "\f25a"; } + +.fa-hand-rock:before { + content: "\f255"; } + +.fa-hand-scissors:before { + content: "\f257"; } + +.fa-hand-spock:before { + content: "\f259"; } + +.fa-hands:before { + content: "\f4c2"; } + +.fa-hands-helping:before { + content: "\f4c4"; } + +.fa-handshake:before { + content: "\f2b5"; } + +.fa-hanukiah:before { + content: "\f6e6"; } + +.fa-hard-hat:before { + content: "\f807"; } + +.fa-hashtag:before { + content: "\f292"; } + +.fa-hat-cowboy:before { + content: "\f8c0"; } + +.fa-hat-cowboy-side:before { + content: "\f8c1"; } + +.fa-hat-wizard:before { + content: "\f6e8"; } + +.fa-hdd:before { + content: "\f0a0"; } + +.fa-heading:before { + content: "\f1dc"; } + +.fa-headphones:before { + content: "\f025"; } + +.fa-headphones-alt:before { + content: "\f58f"; } + +.fa-headset:before { + content: "\f590"; } + +.fa-heart:before { + content: "\f004"; } + +.fa-heart-broken:before { + content: "\f7a9"; } + +.fa-heartbeat:before { + content: "\f21e"; } + +.fa-helicopter:before { + content: "\f533"; } + +.fa-highlighter:before { + content: "\f591"; } + +.fa-hiking:before { + content: "\f6ec"; } + +.fa-hippo:before { + content: "\f6ed"; } + +.fa-hips:before { + content: "\f452"; } + +.fa-hire-a-helper:before { + content: "\f3b0"; } + +.fa-history:before { + content: "\f1da"; } + +.fa-hockey-puck:before { + content: "\f453"; } + +.fa-holly-berry:before { + content: "\f7aa"; } + +.fa-home:before { + content: "\f015"; } + +.fa-hooli:before { + content: "\f427"; } + +.fa-hornbill:before { + content: "\f592"; } + +.fa-horse:before { + content: "\f6f0"; } + +.fa-horse-head:before { + content: "\f7ab"; } + +.fa-hospital:before { + content: "\f0f8"; } + +.fa-hospital-alt:before { + content: "\f47d"; } + +.fa-hospital-symbol:before { + content: "\f47e"; } + +.fa-hot-tub:before { + content: "\f593"; } + +.fa-hotdog:before { + content: "\f80f"; } + +.fa-hotel:before { + content: "\f594"; } + +.fa-hotjar:before { + content: "\f3b1"; } + +.fa-hourglass:before { + content: "\f254"; } + +.fa-hourglass-end:before { + content: "\f253"; } + +.fa-hourglass-half:before { + content: "\f252"; } + +.fa-hourglass-start:before { + content: "\f251"; } + +.fa-house-damage:before { + content: "\f6f1"; } + +.fa-houzz:before { + content: "\f27c"; } + +.fa-hryvnia:before { + content: "\f6f2"; } + +.fa-html5:before { + content: "\f13b"; } + +.fa-hubspot:before { + content: "\f3b2"; } + +.fa-i-cursor:before { + content: "\f246"; } + +.fa-ice-cream:before { + content: "\f810"; } + +.fa-icicles:before { + content: "\f7ad"; } + +.fa-icons:before { + content: "\f86d"; } + +.fa-id-badge:before { + content: "\f2c1"; } + +.fa-id-card:before { + content: "\f2c2"; } + +.fa-id-card-alt:before { + content: "\f47f"; } + +.fa-ideal:before { + content: "\f913"; } + +.fa-igloo:before { + content: "\f7ae"; } + +.fa-image:before { + content: "\f03e"; } + +.fa-images:before { + content: "\f302"; } + +.fa-imdb:before { + content: "\f2d8"; } + +.fa-inbox:before { + content: "\f01c"; } + +.fa-indent:before { + content: "\f03c"; } + +.fa-industry:before { + content: "\f275"; } + +.fa-infinity:before { + content: "\f534"; } + +.fa-info:before { + content: "\f129"; } + +.fa-info-circle:before { + content: "\f05a"; } + +.fa-instagram:before { + content: "\f16d"; } + +.fa-intercom:before { + content: "\f7af"; } + +.fa-internet-explorer:before { + content: "\f26b"; } + +.fa-invision:before { + content: "\f7b0"; } + +.fa-ioxhost:before { + content: "\f208"; } + +.fa-italic:before { + content: "\f033"; } + +.fa-itch-io:before { + content: "\f83a"; } + +.fa-itunes:before { + content: "\f3b4"; } + +.fa-itunes-note:before { + content: "\f3b5"; } + +.fa-java:before { + content: "\f4e4"; } + +.fa-jedi:before { + content: "\f669"; } + +.fa-jedi-order:before { + content: "\f50e"; } + +.fa-jenkins:before { + content: "\f3b6"; } + +.fa-jira:before { + content: "\f7b1"; } + +.fa-joget:before { + content: "\f3b7"; } + +.fa-joint:before { + content: "\f595"; } + +.fa-joomla:before { + content: "\f1aa"; } + +.fa-journal-whills:before { + content: "\f66a"; } + +.fa-js:before { + content: "\f3b8"; } + +.fa-js-square:before { + content: "\f3b9"; } + +.fa-jsfiddle:before { + content: "\f1cc"; } + +.fa-kaaba:before { + content: "\f66b"; } + +.fa-kaggle:before { + content: "\f5fa"; } + +.fa-key:before { + content: "\f084"; } + +.fa-keybase:before { + content: "\f4f5"; } + +.fa-keyboard:before { + content: "\f11c"; } + +.fa-keycdn:before { + content: "\f3ba"; } + +.fa-khanda:before { + content: "\f66d"; } + +.fa-kickstarter:before { + content: "\f3bb"; } + +.fa-kickstarter-k:before { + content: "\f3bc"; } + +.fa-kiss:before { + content: "\f596"; } + +.fa-kiss-beam:before { + content: "\f597"; } + +.fa-kiss-wink-heart:before { + content: "\f598"; } + +.fa-kiwi-bird:before { + content: "\f535"; } + +.fa-korvue:before { + content: "\f42f"; } + +.fa-landmark:before { + content: "\f66f"; } + +.fa-language:before { + content: "\f1ab"; } + +.fa-laptop:before { + content: "\f109"; } + +.fa-laptop-code:before { + content: "\f5fc"; } + +.fa-laptop-medical:before { + content: "\f812"; } + +.fa-laravel:before { + content: "\f3bd"; } + +.fa-lastfm:before { + content: "\f202"; } + +.fa-lastfm-square:before { + content: "\f203"; } + +.fa-laugh:before { + content: "\f599"; } + +.fa-laugh-beam:before { + content: "\f59a"; } + +.fa-laugh-squint:before { + content: "\f59b"; } + +.fa-laugh-wink:before { + content: "\f59c"; } + +.fa-layer-group:before { + content: "\f5fd"; } + +.fa-leaf:before { + content: "\f06c"; } + +.fa-leanpub:before { + content: "\f212"; } + +.fa-lemon:before { + content: "\f094"; } + +.fa-less:before { + content: "\f41d"; } + +.fa-less-than:before { + content: "\f536"; } + +.fa-less-than-equal:before { + content: "\f537"; } + +.fa-level-down-alt:before { + content: "\f3be"; } + +.fa-level-up-alt:before { + content: "\f3bf"; } + +.fa-life-ring:before { + content: "\f1cd"; } + +.fa-lightbulb:before { + content: "\f0eb"; } + +.fa-line:before { + content: "\f3c0"; } + +.fa-link:before { + content: "\f0c1"; } + +.fa-linkedin:before { + content: "\f08c"; } + +.fa-linkedin-in:before { + content: "\f0e1"; } + +.fa-linode:before { + content: "\f2b8"; } + +.fa-linux:before { + content: "\f17c"; } + +.fa-lira-sign:before { + content: "\f195"; } + +.fa-list:before { + content: "\f03a"; } + +.fa-list-alt:before { + content: "\f022"; } + +.fa-list-ol:before { + content: "\f0cb"; } + +.fa-list-ul:before { + content: "\f0ca"; } + +.fa-location-arrow:before { + content: "\f124"; } + +.fa-lock:before { + content: "\f023"; } + +.fa-lock-open:before { + content: "\f3c1"; } + +.fa-long-arrow-alt-down:before { + content: "\f309"; } + +.fa-long-arrow-alt-left:before { + content: "\f30a"; } + +.fa-long-arrow-alt-right:before { + content: "\f30b"; } + +.fa-long-arrow-alt-up:before { + content: "\f30c"; } + +.fa-low-vision:before { + content: "\f2a8"; } + +.fa-luggage-cart:before { + content: "\f59d"; } + +.fa-lyft:before { + content: "\f3c3"; } + +.fa-magento:before { + content: "\f3c4"; } + +.fa-magic:before { + content: "\f0d0"; } + +.fa-magnet:before { + content: "\f076"; } + +.fa-mail-bulk:before { + content: "\f674"; } + +.fa-mailchimp:before { + content: "\f59e"; } + +.fa-male:before { + content: "\f183"; } + +.fa-mandalorian:before { + content: "\f50f"; } + +.fa-map:before { + content: "\f279"; } + +.fa-map-marked:before { + content: "\f59f"; } + +.fa-map-marked-alt:before { + content: "\f5a0"; } + +.fa-map-marker:before { + content: "\f041"; } + +.fa-map-marker-alt:before { + content: "\f3c5"; } + +.fa-map-pin:before { + content: "\f276"; } + +.fa-map-signs:before { + content: "\f277"; } + +.fa-markdown:before { + content: "\f60f"; } + +.fa-marker:before { + content: "\f5a1"; } + +.fa-mars:before { + content: "\f222"; } + +.fa-mars-double:before { + content: "\f227"; } + +.fa-mars-stroke:before { + content: "\f229"; } + +.fa-mars-stroke-h:before { + content: "\f22b"; } + +.fa-mars-stroke-v:before { + content: "\f22a"; } + +.fa-mask:before { + content: "\f6fa"; } + +.fa-mastodon:before { + content: "\f4f6"; } + +.fa-maxcdn:before { + content: "\f136"; } + +.fa-mdb:before { + content: "\f8ca"; } + +.fa-medal:before { + content: "\f5a2"; } + +.fa-medapps:before { + content: "\f3c6"; } + +.fa-medium:before { + content: "\f23a"; } + +.fa-medium-m:before { + content: "\f3c7"; } + +.fa-medkit:before { + content: "\f0fa"; } + +.fa-medrt:before { + content: "\f3c8"; } + +.fa-meetup:before { + content: "\f2e0"; } + +.fa-megaport:before { + content: "\f5a3"; } + +.fa-meh:before { + content: "\f11a"; } + +.fa-meh-blank:before { + content: "\f5a4"; } + +.fa-meh-rolling-eyes:before { + content: "\f5a5"; } + +.fa-memory:before { + content: "\f538"; } + +.fa-mendeley:before { + content: "\f7b3"; } + +.fa-menorah:before { + content: "\f676"; } + +.fa-mercury:before { + content: "\f223"; } + +.fa-meteor:before { + content: "\f753"; } + +.fa-microblog:before { + content: "\f91a"; } + +.fa-microchip:before { + content: "\f2db"; } + +.fa-microphone:before { + content: "\f130"; } + +.fa-microphone-alt:before { + content: "\f3c9"; } + +.fa-microphone-alt-slash:before { + content: "\f539"; } + +.fa-microphone-slash:before { + content: "\f131"; } + +.fa-microscope:before { + content: "\f610"; } + +.fa-microsoft:before { + content: "\f3ca"; } + +.fa-minus:before { + content: "\f068"; } + +.fa-minus-circle:before { + content: "\f056"; } + +.fa-minus-square:before { + content: "\f146"; } + +.fa-mitten:before { + content: "\f7b5"; } + +.fa-mix:before { + content: "\f3cb"; } + +.fa-mixcloud:before { + content: "\f289"; } + +.fa-mizuni:before { + content: "\f3cc"; } + +.fa-mobile:before { + content: "\f10b"; } + +.fa-mobile-alt:before { + content: "\f3cd"; } + +.fa-modx:before { + content: "\f285"; } + +.fa-monero:before { + content: "\f3d0"; } + +.fa-money-bill:before { + content: "\f0d6"; } + +.fa-money-bill-alt:before { + content: "\f3d1"; } + +.fa-money-bill-wave:before { + content: "\f53a"; } + +.fa-money-bill-wave-alt:before { + content: "\f53b"; } + +.fa-money-check:before { + content: "\f53c"; } + +.fa-money-check-alt:before { + content: "\f53d"; } + +.fa-monument:before { + content: "\f5a6"; } + +.fa-moon:before { + content: "\f186"; } + +.fa-mortar-pestle:before { + content: "\f5a7"; } + +.fa-mosque:before { + content: "\f678"; } + +.fa-motorcycle:before { + content: "\f21c"; } + +.fa-mountain:before { + content: "\f6fc"; } + +.fa-mouse:before { + content: "\f8cc"; } + +.fa-mouse-pointer:before { + content: "\f245"; } + +.fa-mug-hot:before { + content: "\f7b6"; } + +.fa-music:before { + content: "\f001"; } + +.fa-napster:before { + content: "\f3d2"; } + +.fa-neos:before { + content: "\f612"; } + +.fa-network-wired:before { + content: "\f6ff"; } + +.fa-neuter:before { + content: "\f22c"; } + +.fa-newspaper:before { + content: "\f1ea"; } + +.fa-nimblr:before { + content: "\f5a8"; } + +.fa-node:before { + content: "\f419"; } + +.fa-node-js:before { + content: "\f3d3"; } + +.fa-not-equal:before { + content: "\f53e"; } + +.fa-notes-medical:before { + content: "\f481"; } + +.fa-npm:before { + content: "\f3d4"; } + +.fa-ns8:before { + content: "\f3d5"; } + +.fa-nutritionix:before { + content: "\f3d6"; } + +.fa-object-group:before { + content: "\f247"; } + +.fa-object-ungroup:before { + content: "\f248"; } + +.fa-odnoklassniki:before { + content: "\f263"; } + +.fa-odnoklassniki-square:before { + content: "\f264"; } + +.fa-oil-can:before { + content: "\f613"; } + +.fa-old-republic:before { + content: "\f510"; } + +.fa-om:before { + content: "\f679"; } + +.fa-opencart:before { + content: "\f23d"; } + +.fa-openid:before { + content: "\f19b"; } + +.fa-opera:before { + content: "\f26a"; } + +.fa-optin-monster:before { + content: "\f23c"; } + +.fa-orcid:before { + content: "\f8d2"; } + +.fa-osi:before { + content: "\f41a"; } + +.fa-otter:before { + content: "\f700"; } + +.fa-outdent:before { + content: "\f03b"; } + +.fa-page4:before { + content: "\f3d7"; } + +.fa-pagelines:before { + content: "\f18c"; } + +.fa-pager:before { + content: "\f815"; } + +.fa-paint-brush:before { + content: "\f1fc"; } + +.fa-paint-roller:before { + content: "\f5aa"; } + +.fa-palette:before { + content: "\f53f"; } + +.fa-palfed:before { + content: "\f3d8"; } + +.fa-pallet:before { + content: "\f482"; } + +.fa-paper-plane:before { + content: "\f1d8"; } + +.fa-paperclip:before { + content: "\f0c6"; } + +.fa-parachute-box:before { + content: "\f4cd"; } + +.fa-paragraph:before { + content: "\f1dd"; } + +.fa-parking:before { + content: "\f540"; } + +.fa-passport:before { + content: "\f5ab"; } + +.fa-pastafarianism:before { + content: "\f67b"; } + +.fa-paste:before { + content: "\f0ea"; } + +.fa-patreon:before { + content: "\f3d9"; } + +.fa-pause:before { + content: "\f04c"; } + +.fa-pause-circle:before { + content: "\f28b"; } + +.fa-paw:before { + content: "\f1b0"; } + +.fa-paypal:before { + content: "\f1ed"; } + +.fa-peace:before { + content: "\f67c"; } + +.fa-pen:before { + content: "\f304"; } + +.fa-pen-alt:before { + content: "\f305"; } + +.fa-pen-fancy:before { + content: "\f5ac"; } + +.fa-pen-nib:before { + content: "\f5ad"; } + +.fa-pen-square:before { + content: "\f14b"; } + +.fa-pencil-alt:before { + content: "\f303"; } + +.fa-pencil-ruler:before { + content: "\f5ae"; } + +.fa-penny-arcade:before { + content: "\f704"; } + +.fa-people-carry:before { + content: "\f4ce"; } + +.fa-pepper-hot:before { + content: "\f816"; } + +.fa-percent:before { + content: "\f295"; } + +.fa-percentage:before { + content: "\f541"; } + +.fa-periscope:before { + content: "\f3da"; } + +.fa-person-booth:before { + content: "\f756"; } + +.fa-phabricator:before { + content: "\f3db"; } + +.fa-phoenix-framework:before { + content: "\f3dc"; } + +.fa-phoenix-squadron:before { + content: "\f511"; } + +.fa-phone:before { + content: "\f095"; } + +.fa-phone-alt:before { + content: "\f879"; } + +.fa-phone-slash:before { + content: "\f3dd"; } + +.fa-phone-square:before { + content: "\f098"; } + +.fa-phone-square-alt:before { + content: "\f87b"; } + +.fa-phone-volume:before { + content: "\f2a0"; } + +.fa-photo-video:before { + content: "\f87c"; } + +.fa-php:before { + content: "\f457"; } + +.fa-pied-piper:before { + content: "\f2ae"; } + +.fa-pied-piper-alt:before { + content: "\f1a8"; } + +.fa-pied-piper-hat:before { + content: "\f4e5"; } + +.fa-pied-piper-pp:before { + content: "\f1a7"; } + +.fa-pied-piper-square:before { + content: "\f91e"; } + +.fa-piggy-bank:before { + content: "\f4d3"; } + +.fa-pills:before { + content: "\f484"; } + +.fa-pinterest:before { + content: "\f0d2"; } + +.fa-pinterest-p:before { + content: "\f231"; } + +.fa-pinterest-square:before { + content: "\f0d3"; } + +.fa-pizza-slice:before { + content: "\f818"; } + +.fa-place-of-worship:before { + content: "\f67f"; } + +.fa-plane:before { + content: "\f072"; } + +.fa-plane-arrival:before { + content: "\f5af"; } + +.fa-plane-departure:before { + content: "\f5b0"; } + +.fa-play:before { + content: "\f04b"; } + +.fa-play-circle:before { + content: "\f144"; } + +.fa-playstation:before { + content: "\f3df"; } + +.fa-plug:before { + content: "\f1e6"; } + +.fa-plus:before { + content: "\f067"; } + +.fa-plus-circle:before { + content: "\f055"; } + +.fa-plus-square:before { + content: "\f0fe"; } + +.fa-podcast:before { + content: "\f2ce"; } + +.fa-poll:before { + content: "\f681"; } + +.fa-poll-h:before { + content: "\f682"; } + +.fa-poo:before { + content: "\f2fe"; } + +.fa-poo-storm:before { + content: "\f75a"; } + +.fa-poop:before { + content: "\f619"; } + +.fa-portrait:before { + content: "\f3e0"; } + +.fa-pound-sign:before { + content: "\f154"; } + +.fa-power-off:before { + content: "\f011"; } + +.fa-pray:before { + content: "\f683"; } + +.fa-praying-hands:before { + content: "\f684"; } + +.fa-prescription:before { + content: "\f5b1"; } + +.fa-prescription-bottle:before { + content: "\f485"; } + +.fa-prescription-bottle-alt:before { + content: "\f486"; } + +.fa-print:before { + content: "\f02f"; } + +.fa-procedures:before { + content: "\f487"; } + +.fa-product-hunt:before { + content: "\f288"; } + +.fa-project-diagram:before { + content: "\f542"; } + +.fa-pushed:before { + content: "\f3e1"; } + +.fa-puzzle-piece:before { + content: "\f12e"; } + +.fa-python:before { + content: "\f3e2"; } + +.fa-qq:before { + content: "\f1d6"; } + +.fa-qrcode:before { + content: "\f029"; } + +.fa-question:before { + content: "\f128"; } + +.fa-question-circle:before { + content: "\f059"; } + +.fa-quidditch:before { + content: "\f458"; } + +.fa-quinscape:before { + content: "\f459"; } + +.fa-quora:before { + content: "\f2c4"; } + +.fa-quote-left:before { + content: "\f10d"; } + +.fa-quote-right:before { + content: "\f10e"; } + +.fa-quran:before { + content: "\f687"; } + +.fa-r-project:before { + content: "\f4f7"; } + +.fa-radiation:before { + content: "\f7b9"; } + +.fa-radiation-alt:before { + content: "\f7ba"; } + +.fa-rainbow:before { + content: "\f75b"; } + +.fa-random:before { + content: "\f074"; } + +.fa-raspberry-pi:before { + content: "\f7bb"; } + +.fa-ravelry:before { + content: "\f2d9"; } + +.fa-react:before { + content: "\f41b"; } + +.fa-reacteurope:before { + content: "\f75d"; } + +.fa-readme:before { + content: "\f4d5"; } + +.fa-rebel:before { + content: "\f1d0"; } + +.fa-receipt:before { + content: "\f543"; } + +.fa-record-vinyl:before { + content: "\f8d9"; } + +.fa-recycle:before { + content: "\f1b8"; } + +.fa-red-river:before { + content: "\f3e3"; } + +.fa-reddit:before { + content: "\f1a1"; } + +.fa-reddit-alien:before { + content: "\f281"; } + +.fa-reddit-square:before { + content: "\f1a2"; } + +.fa-redhat:before { + content: "\f7bc"; } + +.fa-redo:before { + content: "\f01e"; } + +.fa-redo-alt:before { + content: "\f2f9"; } + +.fa-registered:before { + content: "\f25d"; } + +.fa-remove-format:before { + content: "\f87d"; } + +.fa-renren:before { + content: "\f18b"; } + +.fa-reply:before { + content: "\f3e5"; } + +.fa-reply-all:before { + content: "\f122"; } + +.fa-replyd:before { + content: "\f3e6"; } + +.fa-republican:before { + content: "\f75e"; } + +.fa-researchgate:before { + content: "\f4f8"; } + +.fa-resolving:before { + content: "\f3e7"; } + +.fa-restroom:before { + content: "\f7bd"; } + +.fa-retweet:before { + content: "\f079"; } + +.fa-rev:before { + content: "\f5b2"; } + +.fa-ribbon:before { + content: "\f4d6"; } + +.fa-ring:before { + content: "\f70b"; } + +.fa-road:before { + content: "\f018"; } + +.fa-robot:before { + content: "\f544"; } + +.fa-rocket:before { + content: "\f135"; } + +.fa-rocketchat:before { + content: "\f3e8"; } + +.fa-rockrms:before { + content: "\f3e9"; } + +.fa-route:before { + content: "\f4d7"; } + +.fa-rss:before { + content: "\f09e"; } + +.fa-rss-square:before { + content: "\f143"; } + +.fa-ruble-sign:before { + content: "\f158"; } + +.fa-ruler:before { + content: "\f545"; } + +.fa-ruler-combined:before { + content: "\f546"; } + +.fa-ruler-horizontal:before { + content: "\f547"; } + +.fa-ruler-vertical:before { + content: "\f548"; } + +.fa-running:before { + content: "\f70c"; } + +.fa-rupee-sign:before { + content: "\f156"; } + +.fa-sad-cry:before { + content: "\f5b3"; } + +.fa-sad-tear:before { + content: "\f5b4"; } + +.fa-safari:before { + content: "\f267"; } + +.fa-salesforce:before { + content: "\f83b"; } + +.fa-sass:before { + content: "\f41e"; } + +.fa-satellite:before { + content: "\f7bf"; } + +.fa-satellite-dish:before { + content: "\f7c0"; } + +.fa-save:before { + content: "\f0c7"; } + +.fa-schlix:before { + content: "\f3ea"; } + +.fa-school:before { + content: "\f549"; } + +.fa-screwdriver:before { + content: "\f54a"; } + +.fa-scribd:before { + content: "\f28a"; } + +.fa-scroll:before { + content: "\f70e"; } + +.fa-sd-card:before { + content: "\f7c2"; } + +.fa-search:before { + content: "\f002"; } + +.fa-search-dollar:before { + content: "\f688"; } + +.fa-search-location:before { + content: "\f689"; } + +.fa-search-minus:before { + content: "\f010"; } + +.fa-search-plus:before { + content: "\f00e"; } + +.fa-searchengin:before { + content: "\f3eb"; } + +.fa-seedling:before { + content: "\f4d8"; } + +.fa-sellcast:before { + content: "\f2da"; } + +.fa-sellsy:before { + content: "\f213"; } + +.fa-server:before { + content: "\f233"; } + +.fa-servicestack:before { + content: "\f3ec"; } + +.fa-shapes:before { + content: "\f61f"; } + +.fa-share:before { + content: "\f064"; } + +.fa-share-alt:before { + content: "\f1e0"; } + +.fa-share-alt-square:before { + content: "\f1e1"; } + +.fa-share-square:before { + content: "\f14d"; } + +.fa-shekel-sign:before { + content: "\f20b"; } + +.fa-shield-alt:before { + content: "\f3ed"; } + +.fa-ship:before { + content: "\f21a"; } + +.fa-shipping-fast:before { + content: "\f48b"; } + +.fa-shirtsinbulk:before { + content: "\f214"; } + +.fa-shoe-prints:before { + content: "\f54b"; } + +.fa-shopping-bag:before { + content: "\f290"; } + +.fa-shopping-basket:before { + content: "\f291"; } + +.fa-shopping-cart:before { + content: "\f07a"; } + +.fa-shopware:before { + content: "\f5b5"; } + +.fa-shower:before { + content: "\f2cc"; } + +.fa-shuttle-van:before { + content: "\f5b6"; } + +.fa-sign:before { + content: "\f4d9"; } + +.fa-sign-in-alt:before { + content: "\f2f6"; } + +.fa-sign-language:before { + content: "\f2a7"; } + +.fa-sign-out-alt:before { + content: "\f2f5"; } + +.fa-signal:before { + content: "\f012"; } + +.fa-signature:before { + content: "\f5b7"; } + +.fa-sim-card:before { + content: "\f7c4"; } + +.fa-simplybuilt:before { + content: "\f215"; } + +.fa-sistrix:before { + content: "\f3ee"; } + +.fa-sitemap:before { + content: "\f0e8"; } + +.fa-sith:before { + content: "\f512"; } + +.fa-skating:before { + content: "\f7c5"; } + +.fa-sketch:before { + content: "\f7c6"; } + +.fa-skiing:before { + content: "\f7c9"; } + +.fa-skiing-nordic:before { + content: "\f7ca"; } + +.fa-skull:before { + content: "\f54c"; } + +.fa-skull-crossbones:before { + content: "\f714"; } + +.fa-skyatlas:before { + content: "\f216"; } + +.fa-skype:before { + content: "\f17e"; } + +.fa-slack:before { + content: "\f198"; } + +.fa-slack-hash:before { + content: "\f3ef"; } + +.fa-slash:before { + content: "\f715"; } + +.fa-sleigh:before { + content: "\f7cc"; } + +.fa-sliders-h:before { + content: "\f1de"; } + +.fa-slideshare:before { + content: "\f1e7"; } + +.fa-smile:before { + content: "\f118"; } + +.fa-smile-beam:before { + content: "\f5b8"; } + +.fa-smile-wink:before { + content: "\f4da"; } + +.fa-smog:before { + content: "\f75f"; } + +.fa-smoking:before { + content: "\f48d"; } + +.fa-smoking-ban:before { + content: "\f54d"; } + +.fa-sms:before { + content: "\f7cd"; } + +.fa-snapchat:before { + content: "\f2ab"; } + +.fa-snapchat-ghost:before { + content: "\f2ac"; } + +.fa-snapchat-square:before { + content: "\f2ad"; } + +.fa-snowboarding:before { + content: "\f7ce"; } + +.fa-snowflake:before { + content: "\f2dc"; } + +.fa-snowman:before { + content: "\f7d0"; } + +.fa-snowplow:before { + content: "\f7d2"; } + +.fa-socks:before { + content: "\f696"; } + +.fa-solar-panel:before { + content: "\f5ba"; } + +.fa-sort:before { + content: "\f0dc"; } + +.fa-sort-alpha-down:before { + content: "\f15d"; } + +.fa-sort-alpha-down-alt:before { + content: "\f881"; } + +.fa-sort-alpha-up:before { + content: "\f15e"; } + +.fa-sort-alpha-up-alt:before { + content: "\f882"; } + +.fa-sort-amount-down:before { + content: "\f160"; } + +.fa-sort-amount-down-alt:before { + content: "\f884"; } + +.fa-sort-amount-up:before { + content: "\f161"; } + +.fa-sort-amount-up-alt:before { + content: "\f885"; } + +.fa-sort-down:before { + content: "\f0dd"; } + +.fa-sort-numeric-down:before { + content: "\f162"; } + +.fa-sort-numeric-down-alt:before { + content: "\f886"; } + +.fa-sort-numeric-up:before { + content: "\f163"; } + +.fa-sort-numeric-up-alt:before { + content: "\f887"; } + +.fa-sort-up:before { + content: "\f0de"; } + +.fa-soundcloud:before { + content: "\f1be"; } + +.fa-sourcetree:before { + content: "\f7d3"; } + +.fa-spa:before { + content: "\f5bb"; } + +.fa-space-shuttle:before { + content: "\f197"; } + +.fa-speakap:before { + content: "\f3f3"; } + +.fa-speaker-deck:before { + content: "\f83c"; } + +.fa-spell-check:before { + content: "\f891"; } + +.fa-spider:before { + content: "\f717"; } + +.fa-spinner:before { + content: "\f110"; } + +.fa-splotch:before { + content: "\f5bc"; } + +.fa-spotify:before { + content: "\f1bc"; } + +.fa-spray-can:before { + content: "\f5bd"; } + +.fa-square:before { + content: "\f0c8"; } + +.fa-square-full:before { + content: "\f45c"; } + +.fa-square-root-alt:before { + content: "\f698"; } + +.fa-squarespace:before { + content: "\f5be"; } + +.fa-stack-exchange:before { + content: "\f18d"; } + +.fa-stack-overflow:before { + content: "\f16c"; } + +.fa-stackpath:before { + content: "\f842"; } + +.fa-stamp:before { + content: "\f5bf"; } + +.fa-star:before { + content: "\f005"; } + +.fa-star-and-crescent:before { + content: "\f699"; } + +.fa-star-half:before { + content: "\f089"; } + +.fa-star-half-alt:before { + content: "\f5c0"; } + +.fa-star-of-david:before { + content: "\f69a"; } + +.fa-star-of-life:before { + content: "\f621"; } + +.fa-staylinked:before { + content: "\f3f5"; } + +.fa-steam:before { + content: "\f1b6"; } + +.fa-steam-square:before { + content: "\f1b7"; } + +.fa-steam-symbol:before { + content: "\f3f6"; } + +.fa-step-backward:before { + content: "\f048"; } + +.fa-step-forward:before { + content: "\f051"; } + +.fa-stethoscope:before { + content: "\f0f1"; } + +.fa-sticker-mule:before { + content: "\f3f7"; } + +.fa-sticky-note:before { + content: "\f249"; } + +.fa-stop:before { + content: "\f04d"; } + +.fa-stop-circle:before { + content: "\f28d"; } + +.fa-stopwatch:before { + content: "\f2f2"; } + +.fa-store:before { + content: "\f54e"; } + +.fa-store-alt:before { + content: "\f54f"; } + +.fa-strava:before { + content: "\f428"; } + +.fa-stream:before { + content: "\f550"; } + +.fa-street-view:before { + content: "\f21d"; } + +.fa-strikethrough:before { + content: "\f0cc"; } + +.fa-stripe:before { + content: "\f429"; } + +.fa-stripe-s:before { + content: "\f42a"; } + +.fa-stroopwafel:before { + content: "\f551"; } + +.fa-studiovinari:before { + content: "\f3f8"; } + +.fa-stumbleupon:before { + content: "\f1a4"; } + +.fa-stumbleupon-circle:before { + content: "\f1a3"; } + +.fa-subscript:before { + content: "\f12c"; } + +.fa-subway:before { + content: "\f239"; } + +.fa-suitcase:before { + content: "\f0f2"; } + +.fa-suitcase-rolling:before { + content: "\f5c1"; } + +.fa-sun:before { + content: "\f185"; } + +.fa-superpowers:before { + content: "\f2dd"; } + +.fa-superscript:before { + content: "\f12b"; } + +.fa-supple:before { + content: "\f3f9"; } + +.fa-surprise:before { + content: "\f5c2"; } + +.fa-suse:before { + content: "\f7d6"; } + +.fa-swatchbook:before { + content: "\f5c3"; } + +.fa-swift:before { + content: "\f8e1"; } + +.fa-swimmer:before { + content: "\f5c4"; } + +.fa-swimming-pool:before { + content: "\f5c5"; } + +.fa-symfony:before { + content: "\f83d"; } + +.fa-synagogue:before { + content: "\f69b"; } + +.fa-sync:before { + content: "\f021"; } + +.fa-sync-alt:before { + content: "\f2f1"; } + +.fa-syringe:before { + content: "\f48e"; } + +.fa-table:before { + content: "\f0ce"; } + +.fa-table-tennis:before { + content: "\f45d"; } + +.fa-tablet:before { + content: "\f10a"; } + +.fa-tablet-alt:before { + content: "\f3fa"; } + +.fa-tablets:before { + content: "\f490"; } + +.fa-tachometer-alt:before { + content: "\f3fd"; } + +.fa-tag:before { + content: "\f02b"; } + +.fa-tags:before { + content: "\f02c"; } + +.fa-tape:before { + content: "\f4db"; } + +.fa-tasks:before { + content: "\f0ae"; } + +.fa-taxi:before { + content: "\f1ba"; } + +.fa-teamspeak:before { + content: "\f4f9"; } + +.fa-teeth:before { + content: "\f62e"; } + +.fa-teeth-open:before { + content: "\f62f"; } + +.fa-telegram:before { + content: "\f2c6"; } + +.fa-telegram-plane:before { + content: "\f3fe"; } + +.fa-temperature-high:before { + content: "\f769"; } + +.fa-temperature-low:before { + content: "\f76b"; } + +.fa-tencent-weibo:before { + content: "\f1d5"; } + +.fa-tenge:before { + content: "\f7d7"; } + +.fa-terminal:before { + content: "\f120"; } + +.fa-text-height:before { + content: "\f034"; } + +.fa-text-width:before { + content: "\f035"; } + +.fa-th:before { + content: "\f00a"; } + +.fa-th-large:before { + content: "\f009"; } + +.fa-th-list:before { + content: "\f00b"; } + +.fa-the-red-yeti:before { + content: "\f69d"; } + +.fa-theater-masks:before { + content: "\f630"; } + +.fa-themeco:before { + content: "\f5c6"; } + +.fa-themeisle:before { + content: "\f2b2"; } + +.fa-thermometer:before { + content: "\f491"; } + +.fa-thermometer-empty:before { + content: "\f2cb"; } + +.fa-thermometer-full:before { + content: "\f2c7"; } + +.fa-thermometer-half:before { + content: "\f2c9"; } + +.fa-thermometer-quarter:before { + content: "\f2ca"; } + +.fa-thermometer-three-quarters:before { + content: "\f2c8"; } + +.fa-think-peaks:before { + content: "\f731"; } + +.fa-thumbs-down:before { + content: "\f165"; } + +.fa-thumbs-up:before { + content: "\f164"; } + +.fa-thumbtack:before { + content: "\f08d"; } + +.fa-ticket-alt:before { + content: "\f3ff"; } + +.fa-times:before { + content: "\f00d"; } + +.fa-times-circle:before { + content: "\f057"; } + +.fa-tint:before { + content: "\f043"; } + +.fa-tint-slash:before { + content: "\f5c7"; } + +.fa-tired:before { + content: "\f5c8"; } + +.fa-toggle-off:before { + content: "\f204"; } + +.fa-toggle-on:before { + content: "\f205"; } + +.fa-toilet:before { + content: "\f7d8"; } + +.fa-toilet-paper:before { + content: "\f71e"; } + +.fa-toolbox:before { + content: "\f552"; } + +.fa-tools:before { + content: "\f7d9"; } + +.fa-tooth:before { + content: "\f5c9"; } + +.fa-torah:before { + content: "\f6a0"; } + +.fa-torii-gate:before { + content: "\f6a1"; } + +.fa-tractor:before { + content: "\f722"; } + +.fa-trade-federation:before { + content: "\f513"; } + +.fa-trademark:before { + content: "\f25c"; } + +.fa-traffic-light:before { + content: "\f637"; } + +.fa-trailer:before { + content: "\f941"; } + +.fa-train:before { + content: "\f238"; } + +.fa-tram:before { + content: "\f7da"; } + +.fa-transgender:before { + content: "\f224"; } + +.fa-transgender-alt:before { + content: "\f225"; } + +.fa-trash:before { + content: "\f1f8"; } + +.fa-trash-alt:before { + content: "\f2ed"; } + +.fa-trash-restore:before { + content: "\f829"; } + +.fa-trash-restore-alt:before { + content: "\f82a"; } + +.fa-tree:before { + content: "\f1bb"; } + +.fa-trello:before { + content: "\f181"; } + +.fa-tripadvisor:before { + content: "\f262"; } + +.fa-trophy:before { + content: "\f091"; } + +.fa-truck:before { + content: "\f0d1"; } + +.fa-truck-loading:before { + content: "\f4de"; } + +.fa-truck-monster:before { + content: "\f63b"; } + +.fa-truck-moving:before { + content: "\f4df"; } + +.fa-truck-pickup:before { + content: "\f63c"; } + +.fa-tshirt:before { + content: "\f553"; } + +.fa-tty:before { + content: "\f1e4"; } + +.fa-tumblr:before { + content: "\f173"; } + +.fa-tumblr-square:before { + content: "\f174"; } + +.fa-tv:before { + content: "\f26c"; } + +.fa-twitch:before { + content: "\f1e8"; } + +.fa-twitter:before { + content: "\f099"; } + +.fa-twitter-square:before { + content: "\f081"; } + +.fa-typo3:before { + content: "\f42b"; } + +.fa-uber:before { + content: "\f402"; } + +.fa-ubuntu:before { + content: "\f7df"; } + +.fa-uikit:before { + content: "\f403"; } + +.fa-umbraco:before { + content: "\f8e8"; } + +.fa-umbrella:before { + content: "\f0e9"; } + +.fa-umbrella-beach:before { + content: "\f5ca"; } + +.fa-underline:before { + content: "\f0cd"; } + +.fa-undo:before { + content: "\f0e2"; } + +.fa-undo-alt:before { + content: "\f2ea"; } + +.fa-uniregistry:before { + content: "\f404"; } + +.fa-unity:before { + content: "\f949"; } + +.fa-universal-access:before { + content: "\f29a"; } + +.fa-university:before { + content: "\f19c"; } + +.fa-unlink:before { + content: "\f127"; } + +.fa-unlock:before { + content: "\f09c"; } + +.fa-unlock-alt:before { + content: "\f13e"; } + +.fa-untappd:before { + content: "\f405"; } + +.fa-upload:before { + content: "\f093"; } + +.fa-ups:before { + content: "\f7e0"; } + +.fa-usb:before { + content: "\f287"; } + +.fa-user:before { + content: "\f007"; } + +.fa-user-alt:before { + content: "\f406"; } + +.fa-user-alt-slash:before { + content: "\f4fa"; } + +.fa-user-astronaut:before { + content: "\f4fb"; } + +.fa-user-check:before { + content: "\f4fc"; } + +.fa-user-circle:before { + content: "\f2bd"; } + +.fa-user-clock:before { + content: "\f4fd"; } + +.fa-user-cog:before { + content: "\f4fe"; } + +.fa-user-edit:before { + content: "\f4ff"; } + +.fa-user-friends:before { + content: "\f500"; } + +.fa-user-graduate:before { + content: "\f501"; } + +.fa-user-injured:before { + content: "\f728"; } + +.fa-user-lock:before { + content: "\f502"; } + +.fa-user-md:before { + content: "\f0f0"; } + +.fa-user-minus:before { + content: "\f503"; } + +.fa-user-ninja:before { + content: "\f504"; } + +.fa-user-nurse:before { + content: "\f82f"; } + +.fa-user-plus:before { + content: "\f234"; } + +.fa-user-secret:before { + content: "\f21b"; } + +.fa-user-shield:before { + content: "\f505"; } + +.fa-user-slash:before { + content: "\f506"; } + +.fa-user-tag:before { + content: "\f507"; } + +.fa-user-tie:before { + content: "\f508"; } + +.fa-user-times:before { + content: "\f235"; } + +.fa-users:before { + content: "\f0c0"; } + +.fa-users-cog:before { + content: "\f509"; } + +.fa-usps:before { + content: "\f7e1"; } + +.fa-ussunnah:before { + content: "\f407"; } + +.fa-utensil-spoon:before { + content: "\f2e5"; } + +.fa-utensils:before { + content: "\f2e7"; } + +.fa-vaadin:before { + content: "\f408"; } + +.fa-vector-square:before { + content: "\f5cb"; } + +.fa-venus:before { + content: "\f221"; } + +.fa-venus-double:before { + content: "\f226"; } + +.fa-venus-mars:before { + content: "\f228"; } + +.fa-viacoin:before { + content: "\f237"; } + +.fa-viadeo:before { + content: "\f2a9"; } + +.fa-viadeo-square:before { + content: "\f2aa"; } + +.fa-vial:before { + content: "\f492"; } + +.fa-vials:before { + content: "\f493"; } + +.fa-viber:before { + content: "\f409"; } + +.fa-video:before { + content: "\f03d"; } + +.fa-video-slash:before { + content: "\f4e2"; } + +.fa-vihara:before { + content: "\f6a7"; } + +.fa-vimeo:before { + content: "\f40a"; } + +.fa-vimeo-square:before { + content: "\f194"; } + +.fa-vimeo-v:before { + content: "\f27d"; } + +.fa-vine:before { + content: "\f1ca"; } + +.fa-vk:before { + content: "\f189"; } + +.fa-vnv:before { + content: "\f40b"; } + +.fa-voicemail:before { + content: "\f897"; } + +.fa-volleyball-ball:before { + content: "\f45f"; } + +.fa-volume-down:before { + content: "\f027"; } + +.fa-volume-mute:before { + content: "\f6a9"; } + +.fa-volume-off:before { + content: "\f026"; } + +.fa-volume-up:before { + content: "\f028"; } + +.fa-vote-yea:before { + content: "\f772"; } + +.fa-vr-cardboard:before { + content: "\f729"; } + +.fa-vuejs:before { + content: "\f41f"; } + +.fa-walking:before { + content: "\f554"; } + +.fa-wallet:before { + content: "\f555"; } + +.fa-warehouse:before { + content: "\f494"; } + +.fa-water:before { + content: "\f773"; } + +.fa-wave-square:before { + content: "\f83e"; } + +.fa-waze:before { + content: "\f83f"; } + +.fa-weebly:before { + content: "\f5cc"; } + +.fa-weibo:before { + content: "\f18a"; } + +.fa-weight:before { + content: "\f496"; } + +.fa-weight-hanging:before { + content: "\f5cd"; } + +.fa-weixin:before { + content: "\f1d7"; } + +.fa-whatsapp:before { + content: "\f232"; } + +.fa-whatsapp-square:before { + content: "\f40c"; } + +.fa-wheelchair:before { + content: "\f193"; } + +.fa-whmcs:before { + content: "\f40d"; } + +.fa-wifi:before { + content: "\f1eb"; } + +.fa-wikipedia-w:before { + content: "\f266"; } + +.fa-wind:before { + content: "\f72e"; } + +.fa-window-close:before { + content: "\f410"; } + +.fa-window-maximize:before { + content: "\f2d0"; } + +.fa-window-minimize:before { + content: "\f2d1"; } + +.fa-window-restore:before { + content: "\f2d2"; } + +.fa-windows:before { + content: "\f17a"; } + +.fa-wine-bottle:before { + content: "\f72f"; } + +.fa-wine-glass:before { + content: "\f4e3"; } + +.fa-wine-glass-alt:before { + content: "\f5ce"; } + +.fa-wix:before { + content: "\f5cf"; } + +.fa-wizards-of-the-coast:before { + content: "\f730"; } + +.fa-wolf-pack-battalion:before { + content: "\f514"; } + +.fa-won-sign:before { + content: "\f159"; } + +.fa-wordpress:before { + content: "\f19a"; } + +.fa-wordpress-simple:before { + content: "\f411"; } + +.fa-wpbeginner:before { + content: "\f297"; } + +.fa-wpexplorer:before { + content: "\f2de"; } + +.fa-wpforms:before { + content: "\f298"; } + +.fa-wpressr:before { + content: "\f3e4"; } + +.fa-wrench:before { + content: "\f0ad"; } + +.fa-x-ray:before { + content: "\f497"; } + +.fa-xbox:before { + content: "\f412"; } + +.fa-xing:before { + content: "\f168"; } + +.fa-xing-square:before { + content: "\f169"; } + +.fa-y-combinator:before { + content: "\f23b"; } + +.fa-yahoo:before { + content: "\f19e"; } + +.fa-yammer:before { + content: "\f840"; } + +.fa-yandex:before { + content: "\f413"; } + +.fa-yandex-international:before { + content: "\f414"; } + +.fa-yarn:before { + content: "\f7e3"; } + +.fa-yelp:before { + content: "\f1e9"; } + +.fa-yen-sign:before { + content: "\f157"; } + +.fa-yin-yang:before { + content: "\f6ad"; } + +.fa-yoast:before { + content: "\f2b1"; } + +.fa-youtube:before { + content: "\f167"; } + +.fa-youtube-square:before { + content: "\f431"; } + +.fa-zhihu:before { + content: "\f63f"; } + +.sr-only { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + +.sr-only-focusable:active, .sr-only-focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/fontawesome.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/fontawesome.min.css new file mode 100644 index 00000000..5beb7b1b --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/fontawesome.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\f907"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\f913"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\f91a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\f91e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\f941"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\f949"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/regular.css b/templates/map/client/libs/fontawesome/5.12.0/css/regular.css new file mode 100644 index 00000000..5978ab61 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/regular.css @@ -0,0 +1,15 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 400; + font-display: auto; + src: url("../webfonts/fa-regular-400.eot"); + src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); } + +.far { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/regular.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/regular.min.css new file mode 100644 index 00000000..bde811c3 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/regular.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/solid.css b/templates/map/client/libs/fontawesome/5.12.0/css/solid.css new file mode 100644 index 00000000..27d1844b --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/solid.css @@ -0,0 +1,16 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 900; + font-display: auto; + src: url("../webfonts/fa-solid-900.eot"); + src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } + +.fa, +.fas { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/solid.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/solid.min.css new file mode 100644 index 00000000..cfdd5a7a --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/solid.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/svg-with-js.css b/templates/map/client/libs/fontawesome/5.12.0/css/svg-with-js.css new file mode 100644 index 00000000..8a4af47e --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/svg-with-js.css @@ -0,0 +1,371 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +svg:not(:root).svg-inline--fa { + overflow: visible; } + +.svg-inline--fa { + display: inline-block; + font-size: inherit; + height: 1em; + overflow: visible; + vertical-align: -.125em; } + .svg-inline--fa.fa-lg { + vertical-align: -.225em; } + .svg-inline--fa.fa-w-1 { + width: 0.0625em; } + .svg-inline--fa.fa-w-2 { + width: 0.125em; } + .svg-inline--fa.fa-w-3 { + width: 0.1875em; } + .svg-inline--fa.fa-w-4 { + width: 0.25em; } + .svg-inline--fa.fa-w-5 { + width: 0.3125em; } + .svg-inline--fa.fa-w-6 { + width: 0.375em; } + .svg-inline--fa.fa-w-7 { + width: 0.4375em; } + .svg-inline--fa.fa-w-8 { + width: 0.5em; } + .svg-inline--fa.fa-w-9 { + width: 0.5625em; } + .svg-inline--fa.fa-w-10 { + width: 0.625em; } + .svg-inline--fa.fa-w-11 { + width: 0.6875em; } + .svg-inline--fa.fa-w-12 { + width: 0.75em; } + .svg-inline--fa.fa-w-13 { + width: 0.8125em; } + .svg-inline--fa.fa-w-14 { + width: 0.875em; } + .svg-inline--fa.fa-w-15 { + width: 0.9375em; } + .svg-inline--fa.fa-w-16 { + width: 1em; } + .svg-inline--fa.fa-w-17 { + width: 1.0625em; } + .svg-inline--fa.fa-w-18 { + width: 1.125em; } + .svg-inline--fa.fa-w-19 { + width: 1.1875em; } + .svg-inline--fa.fa-w-20 { + width: 1.25em; } + .svg-inline--fa.fa-pull-left { + margin-right: .3em; + width: auto; } + .svg-inline--fa.fa-pull-right { + margin-left: .3em; + width: auto; } + .svg-inline--fa.fa-border { + height: 1.5em; } + .svg-inline--fa.fa-li { + width: 2em; } + .svg-inline--fa.fa-fw { + width: 1.25em; } + +.fa-layers svg.svg-inline--fa { + bottom: 0; + left: 0; + margin: auto; + position: absolute; + right: 0; + top: 0; } + +.fa-layers { + display: inline-block; + height: 1em; + position: relative; + text-align: center; + vertical-align: -.125em; + width: 1em; } + .fa-layers svg.svg-inline--fa { + -webkit-transform-origin: center center; + transform-origin: center center; } + +.fa-layers-text, .fa-layers-counter { + display: inline-block; + position: absolute; + text-align: center; } + +.fa-layers-text { + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + -webkit-transform-origin: center center; + transform-origin: center center; } + +.fa-layers-counter { + background-color: #ff253a; + border-radius: 1em; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: #fff; + height: 1.5em; + line-height: 1; + max-width: 5em; + min-width: 1.5em; + overflow: hidden; + padding: .25em; + right: 0; + text-overflow: ellipsis; + top: 0; + -webkit-transform: scale(0.25); + transform: scale(0.25); + -webkit-transform-origin: top right; + transform-origin: top right; } + +.fa-layers-bottom-right { + bottom: 0; + right: 0; + top: auto; + -webkit-transform: scale(0.25); + transform: scale(0.25); + -webkit-transform-origin: bottom right; + transform-origin: bottom right; } + +.fa-layers-bottom-left { + bottom: 0; + left: 0; + right: auto; + top: auto; + -webkit-transform: scale(0.25); + transform: scale(0.25); + -webkit-transform-origin: bottom left; + transform-origin: bottom left; } + +.fa-layers-top-right { + right: 0; + top: 0; + -webkit-transform: scale(0.25); + transform: scale(0.25); + -webkit-transform-origin: top right; + transform-origin: top right; } + +.fa-layers-top-left { + left: 0; + right: auto; + top: 0; + -webkit-transform: scale(0.25); + transform: scale(0.25); + -webkit-transform-origin: top left; + transform-origin: top left; } + +.fa-lg { + font-size: 1.33333em; + line-height: 0.75em; + vertical-align: -.0667em; } + +.fa-xs { + font-size: .75em; } + +.fa-sm { + font-size: .875em; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: 2.5em; + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: -2em; + position: absolute; + text-align: center; + width: 2em; + line-height: inherit; } + +.fa-border { + border: solid 0.08em #eee; + border-radius: .1em; + padding: .2em .25em .15em; } + +.fa-pull-left { + float: left; } + +.fa-pull-right { + float: right; } + +.fa.fa-pull-left, +.fas.fa-pull-left, +.far.fa-pull-left, +.fal.fa-pull-left, +.fab.fa-pull-left { + margin-right: .3em; } + +.fa.fa-pull-right, +.fas.fa-pull-right, +.far.fa-pull-right, +.fal.fa-pull-right, +.fab.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(360deg); + transform: rotate(360deg); } } + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); } + +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-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); + transform: scale(1, -1); } + +.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-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, +:root .fa-flip-both { + -webkit-filter: none; + filter: none; } + +.fa-stack { + display: inline-block; + height: 2em; + position: relative; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + bottom: 0; + left: 0; + margin: auto; + position: absolute; + right: 0; + top: 0; } + +.svg-inline--fa.fa-stack-1x { + height: 1em; + width: 1.25em; } + +.svg-inline--fa.fa-stack-2x { + height: 2em; + width: 2.5em; } + +.fa-inverse { + color: #fff; } + +.sr-only { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + +.sr-only-focusable:active, .sr-only-focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; } + +.svg-inline--fa .fa-primary { + fill: var(--fa-primary-color, currentColor); + opacity: 1; + opacity: var(--fa-primary-opacity, 1); } + +.svg-inline--fa .fa-secondary { + fill: var(--fa-secondary-color, currentColor); + opacity: 0.4; + opacity: var(--fa-secondary-opacity, 0.4); } + +.svg-inline--fa.fa-swap-opacity .fa-primary { + opacity: 0.4; + opacity: var(--fa-secondary-opacity, 0.4); } + +.svg-inline--fa.fa-swap-opacity .fa-secondary { + opacity: 1; + opacity: var(--fa-primary-opacity, 1); } + +.svg-inline--fa mask .fa-primary, +.svg-inline--fa mask .fa-secondary { + fill: black; } + +.fad.fa-inverse { + color: #fff; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/svg-with-js.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/svg-with-js.min.css new file mode 100644 index 00000000..096d2f7e --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/svg-with-js.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor)}.svg-inline--fa .fa-secondary,.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fad.fa-inverse{color:#fff} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/v4-shims.css b/templates/map/client/libs/fontawesome/5.12.0/css/v4-shims.css new file mode 100644 index 00000000..982cb034 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/v4-shims.css @@ -0,0 +1,2172 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa.fa-glass:before { + content: "\f000"; } + +.fa.fa-meetup { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-star-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-star-o:before { + content: "\f005"; } + +.fa.fa-remove:before { + content: "\f00d"; } + +.fa.fa-close:before { + content: "\f00d"; } + +.fa.fa-gear:before { + content: "\f013"; } + +.fa.fa-trash-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-trash-o:before { + content: "\f2ed"; } + +.fa.fa-file-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-o:before { + content: "\f15b"; } + +.fa.fa-clock-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-clock-o:before { + content: "\f017"; } + +.fa.fa-arrow-circle-o-down { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-down:before { + content: "\f358"; } + +.fa.fa-arrow-circle-o-up { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-up:before { + content: "\f35b"; } + +.fa.fa-play-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-play-circle-o:before { + content: "\f144"; } + +.fa.fa-repeat:before { + content: "\f01e"; } + +.fa.fa-rotate-right:before { + content: "\f01e"; } + +.fa.fa-refresh:before { + content: "\f021"; } + +.fa.fa-list-alt { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-dedent:before { + content: "\f03b"; } + +.fa.fa-video-camera:before { + content: "\f03d"; } + +.fa.fa-picture-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-picture-o:before { + content: "\f03e"; } + +.fa.fa-photo { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-photo:before { + content: "\f03e"; } + +.fa.fa-image { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-image:before { + content: "\f03e"; } + +.fa.fa-pencil:before { + content: "\f303"; } + +.fa.fa-map-marker:before { + content: "\f3c5"; } + +.fa.fa-pencil-square-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-pencil-square-o:before { + content: "\f044"; } + +.fa.fa-share-square-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-share-square-o:before { + content: "\f14d"; } + +.fa.fa-check-square-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-check-square-o:before { + content: "\f14a"; } + +.fa.fa-arrows:before { + content: "\f0b2"; } + +.fa.fa-times-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-times-circle-o:before { + content: "\f057"; } + +.fa.fa-check-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-check-circle-o:before { + content: "\f058"; } + +.fa.fa-mail-forward:before { + content: "\f064"; } + +.fa.fa-expand:before { + content: "\f424"; } + +.fa.fa-compress:before { + content: "\f422"; } + +.fa.fa-eye { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-eye-slash { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-warning:before { + content: "\f071"; } + +.fa.fa-calendar:before { + content: "\f073"; } + +.fa.fa-arrows-v:before { + content: "\f338"; } + +.fa.fa-arrows-h:before { + content: "\f337"; } + +.fa.fa-bar-chart { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-bar-chart:before { + content: "\f080"; } + +.fa.fa-bar-chart-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-bar-chart-o:before { + content: "\f080"; } + +.fa.fa-twitter-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-facebook-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gears:before { + content: "\f085"; } + +.fa.fa-thumbs-o-up { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-up:before { + content: "\f164"; } + +.fa.fa-thumbs-o-down { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-down:before { + content: "\f165"; } + +.fa.fa-heart-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-heart-o:before { + content: "\f004"; } + +.fa.fa-sign-out:before { + content: "\f2f5"; } + +.fa.fa-linkedin-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-linkedin-square:before { + content: "\f08c"; } + +.fa.fa-thumb-tack:before { + content: "\f08d"; } + +.fa.fa-external-link:before { + content: "\f35d"; } + +.fa.fa-sign-in:before { + content: "\f2f6"; } + +.fa.fa-github-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-lemon-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-lemon-o:before { + content: "\f094"; } + +.fa.fa-square-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-square-o:before { + content: "\f0c8"; } + +.fa.fa-bookmark-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-bookmark-o:before { + content: "\f02e"; } + +.fa.fa-twitter { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-facebook:before { + content: "\f39e"; } + +.fa.fa-facebook-f { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-facebook-f:before { + content: "\f39e"; } + +.fa.fa-github { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-credit-card { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-feed:before { + content: "\f09e"; } + +.fa.fa-hdd-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hdd-o:before { + content: "\f0a0"; } + +.fa.fa-hand-o-right { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-o-right:before { + content: "\f0a4"; } + +.fa.fa-hand-o-left { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-o-left:before { + content: "\f0a5"; } + +.fa.fa-hand-o-up { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-o-up:before { + content: "\f0a6"; } + +.fa.fa-hand-o-down { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-o-down:before { + content: "\f0a7"; } + +.fa.fa-arrows-alt:before { + content: "\f31e"; } + +.fa.fa-group:before { + content: "\f0c0"; } + +.fa.fa-chain:before { + content: "\f0c1"; } + +.fa.fa-scissors:before { + content: "\f0c4"; } + +.fa.fa-files-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-files-o:before { + content: "\f0c5"; } + +.fa.fa-floppy-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-floppy-o:before { + content: "\f0c7"; } + +.fa.fa-navicon:before { + content: "\f0c9"; } + +.fa.fa-reorder:before { + content: "\f0c9"; } + +.fa.fa-pinterest { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-plus { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-plus:before { + content: "\f0d5"; } + +.fa.fa-money { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-money:before { + content: "\f3d1"; } + +.fa.fa-unsorted:before { + content: "\f0dc"; } + +.fa.fa-sort-desc:before { + content: "\f0dd"; } + +.fa.fa-sort-asc:before { + content: "\f0de"; } + +.fa.fa-linkedin { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-linkedin:before { + content: "\f0e1"; } + +.fa.fa-rotate-left:before { + content: "\f0e2"; } + +.fa.fa-legal:before { + content: "\f0e3"; } + +.fa.fa-tachometer:before { + content: "\f3fd"; } + +.fa.fa-dashboard:before { + content: "\f3fd"; } + +.fa.fa-comment-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-comment-o:before { + content: "\f075"; } + +.fa.fa-comments-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-comments-o:before { + content: "\f086"; } + +.fa.fa-flash:before { + content: "\f0e7"; } + +.fa.fa-clipboard { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-paste { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-paste:before { + content: "\f328"; } + +.fa.fa-lightbulb-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-lightbulb-o:before { + content: "\f0eb"; } + +.fa.fa-exchange:before { + content: "\f362"; } + +.fa.fa-cloud-download:before { + content: "\f381"; } + +.fa.fa-cloud-upload:before { + content: "\f382"; } + +.fa.fa-bell-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-bell-o:before { + content: "\f0f3"; } + +.fa.fa-cutlery:before { + content: "\f2e7"; } + +.fa.fa-file-text-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-text-o:before { + content: "\f15c"; } + +.fa.fa-building-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-building-o:before { + content: "\f1ad"; } + +.fa.fa-hospital-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hospital-o:before { + content: "\f0f8"; } + +.fa.fa-tablet:before { + content: "\f3fa"; } + +.fa.fa-mobile:before { + content: "\f3cd"; } + +.fa.fa-mobile-phone:before { + content: "\f3cd"; } + +.fa.fa-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-circle-o:before { + content: "\f111"; } + +.fa.fa-mail-reply:before { + content: "\f3e5"; } + +.fa.fa-github-alt { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-folder-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-folder-o:before { + content: "\f07b"; } + +.fa.fa-folder-open-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-folder-open-o:before { + content: "\f07c"; } + +.fa.fa-smile-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-smile-o:before { + content: "\f118"; } + +.fa.fa-frown-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-frown-o:before { + content: "\f119"; } + +.fa.fa-meh-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-meh-o:before { + content: "\f11a"; } + +.fa.fa-keyboard-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-keyboard-o:before { + content: "\f11c"; } + +.fa.fa-flag-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-flag-o:before { + content: "\f024"; } + +.fa.fa-mail-reply-all:before { + content: "\f122"; } + +.fa.fa-star-half-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-star-half-o:before { + content: "\f089"; } + +.fa.fa-star-half-empty { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-star-half-empty:before { + content: "\f089"; } + +.fa.fa-star-half-full { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-star-half-full:before { + content: "\f089"; } + +.fa.fa-code-fork:before { + content: "\f126"; } + +.fa.fa-chain-broken:before { + content: "\f127"; } + +.fa.fa-shield:before { + content: "\f3ed"; } + +.fa.fa-calendar-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-calendar-o:before { + content: "\f133"; } + +.fa.fa-maxcdn { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-html5 { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-css3 { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ticket:before { + content: "\f3ff"; } + +.fa.fa-minus-square-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-minus-square-o:before { + content: "\f146"; } + +.fa.fa-level-up:before { + content: "\f3bf"; } + +.fa.fa-level-down:before { + content: "\f3be"; } + +.fa.fa-pencil-square:before { + content: "\f14b"; } + +.fa.fa-external-link-square:before { + content: "\f360"; } + +.fa.fa-compass { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down:before { + content: "\f150"; } + +.fa.fa-toggle-down { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-toggle-down:before { + content: "\f150"; } + +.fa.fa-caret-square-o-up { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-up:before { + content: "\f151"; } + +.fa.fa-toggle-up { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-toggle-up:before { + content: "\f151"; } + +.fa.fa-caret-square-o-right { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-right:before { + content: "\f152"; } + +.fa.fa-toggle-right { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-toggle-right:before { + content: "\f152"; } + +.fa.fa-eur:before { + content: "\f153"; } + +.fa.fa-euro:before { + content: "\f153"; } + +.fa.fa-gbp:before { + content: "\f154"; } + +.fa.fa-usd:before { + content: "\f155"; } + +.fa.fa-dollar:before { + content: "\f155"; } + +.fa.fa-inr:before { + content: "\f156"; } + +.fa.fa-rupee:before { + content: "\f156"; } + +.fa.fa-jpy:before { + content: "\f157"; } + +.fa.fa-cny:before { + content: "\f157"; } + +.fa.fa-rmb:before { + content: "\f157"; } + +.fa.fa-yen:before { + content: "\f157"; } + +.fa.fa-rub:before { + content: "\f158"; } + +.fa.fa-ruble:before { + content: "\f158"; } + +.fa.fa-rouble:before { + content: "\f158"; } + +.fa.fa-krw:before { + content: "\f159"; } + +.fa.fa-won:before { + content: "\f159"; } + +.fa.fa-btc { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin:before { + content: "\f15a"; } + +.fa.fa-file-text:before { + content: "\f15c"; } + +.fa.fa-sort-alpha-asc:before { + content: "\f15d"; } + +.fa.fa-sort-alpha-desc:before { + content: "\f881"; } + +.fa.fa-sort-amount-asc:before { + content: "\f160"; } + +.fa.fa-sort-amount-desc:before { + content: "\f884"; } + +.fa.fa-sort-numeric-asc:before { + content: "\f162"; } + +.fa.fa-sort-numeric-desc:before { + content: "\f886"; } + +.fa.fa-youtube-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-youtube { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-xing { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-youtube-play { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-youtube-play:before { + content: "\f167"; } + +.fa.fa-dropbox { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-stack-overflow { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-instagram { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-flickr { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-adn { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square:before { + content: "\f171"; } + +.fa.fa-tumblr { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-long-arrow-down:before { + content: "\f309"; } + +.fa.fa-long-arrow-up:before { + content: "\f30c"; } + +.fa.fa-long-arrow-left:before { + content: "\f30a"; } + +.fa.fa-long-arrow-right:before { + content: "\f30b"; } + +.fa.fa-apple { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-windows { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-android { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-linux { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-dribbble { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-skype { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-foursquare { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-trello { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gratipay { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gittip:before { + content: "\f184"; } + +.fa.fa-sun-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-sun-o:before { + content: "\f185"; } + +.fa.fa-moon-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-moon-o:before { + content: "\f186"; } + +.fa.fa-vk { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-weibo { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-renren { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-pagelines { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-stack-exchange { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right:before { + content: "\f35a"; } + +.fa.fa-arrow-circle-o-left { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-left:before { + content: "\f359"; } + +.fa.fa-caret-square-o-left { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-left:before { + content: "\f191"; } + +.fa.fa-toggle-left { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-toggle-left:before { + content: "\f191"; } + +.fa.fa-dot-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-dot-circle-o:before { + content: "\f192"; } + +.fa.fa-vimeo-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-try:before { + content: "\f195"; } + +.fa.fa-turkish-lira:before { + content: "\f195"; } + +.fa.fa-plus-square-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-plus-square-o:before { + content: "\f0fe"; } + +.fa.fa-slack { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wordpress { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-openid { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-institution:before { + content: "\f19c"; } + +.fa.fa-bank:before { + content: "\f19c"; } + +.fa.fa-mortar-board:before { + content: "\f19d"; } + +.fa.fa-yahoo { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-reddit { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-stumbleupon-circle { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-stumbleupon { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-delicious { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-digg { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-pp { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-alt { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-drupal { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-joomla { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-spoon:before { + content: "\f2e5"; } + +.fa.fa-behance { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-steam { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-automobile:before { + content: "\f1b9"; } + +.fa.fa-envelope-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-envelope-o:before { + content: "\f0e0"; } + +.fa.fa-spotify { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-deviantart { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-soundcloud { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-pdf-o:before { + content: "\f1c1"; } + +.fa.fa-file-word-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-word-o:before { + content: "\f1c2"; } + +.fa.fa-file-excel-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-excel-o:before { + content: "\f1c3"; } + +.fa.fa-file-powerpoint-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-powerpoint-o:before { + content: "\f1c4"; } + +.fa.fa-file-image-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-image-o:before { + content: "\f1c5"; } + +.fa.fa-file-photo-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-photo-o:before { + content: "\f1c5"; } + +.fa.fa-file-picture-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-picture-o:before { + content: "\f1c5"; } + +.fa.fa-file-archive-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-archive-o:before { + content: "\f1c6"; } + +.fa.fa-file-zip-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-zip-o:before { + content: "\f1c6"; } + +.fa.fa-file-audio-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-audio-o:before { + content: "\f1c7"; } + +.fa.fa-file-sound-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-sound-o:before { + content: "\f1c7"; } + +.fa.fa-file-video-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-video-o:before { + content: "\f1c8"; } + +.fa.fa-file-movie-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-movie-o:before { + content: "\f1c8"; } + +.fa.fa-file-code-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-file-code-o:before { + content: "\f1c9"; } + +.fa.fa-vine { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-codepen { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-jsfiddle { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-life-ring { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-life-bouy { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-life-bouy:before { + content: "\f1cd"; } + +.fa.fa-life-buoy { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-life-buoy:before { + content: "\f1cd"; } + +.fa.fa-life-saver { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-life-saver:before { + content: "\f1cd"; } + +.fa.fa-support { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-support:before { + content: "\f1cd"; } + +.fa.fa-circle-o-notch:before { + content: "\f1ce"; } + +.fa.fa-rebel { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ra { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ra:before { + content: "\f1d0"; } + +.fa.fa-resistance { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-resistance:before { + content: "\f1d0"; } + +.fa.fa-empire { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ge { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ge:before { + content: "\f1d1"; } + +.fa.fa-git-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-git { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-hacker-news { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square:before { + content: "\f1d4"; } + +.fa.fa-yc-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-yc-square:before { + content: "\f1d4"; } + +.fa.fa-tencent-weibo { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-qq { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-weixin { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wechat:before { + content: "\f1d7"; } + +.fa.fa-send:before { + content: "\f1d8"; } + +.fa.fa-paper-plane-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-paper-plane-o:before { + content: "\f1d8"; } + +.fa.fa-send-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-send-o:before { + content: "\f1d8"; } + +.fa.fa-circle-thin { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-circle-thin:before { + content: "\f111"; } + +.fa.fa-header:before { + content: "\f1dc"; } + +.fa.fa-sliders:before { + content: "\f1de"; } + +.fa.fa-futbol-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-futbol-o:before { + content: "\f1e3"; } + +.fa.fa-soccer-ball-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-soccer-ball-o:before { + content: "\f1e3"; } + +.fa.fa-slideshare { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-twitch { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-yelp { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-newspaper-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-newspaper-o:before { + content: "\f1ea"; } + +.fa.fa-paypal { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-wallet { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-visa { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-mastercard { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-discover { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-amex { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-paypal { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-stripe { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-bell-slash-o:before { + content: "\f1f6"; } + +.fa.fa-trash:before { + content: "\f2ed"; } + +.fa.fa-copyright { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-eyedropper:before { + content: "\f1fb"; } + +.fa.fa-area-chart:before { + content: "\f1fe"; } + +.fa.fa-pie-chart:before { + content: "\f200"; } + +.fa.fa-line-chart:before { + content: "\f201"; } + +.fa.fa-lastfm { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ioxhost { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-angellist { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-cc:before { + content: "\f20a"; } + +.fa.fa-ils:before { + content: "\f20b"; } + +.fa.fa-shekel:before { + content: "\f20b"; } + +.fa.fa-sheqel:before { + content: "\f20b"; } + +.fa.fa-meanpath { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-meanpath:before { + content: "\f2b4"; } + +.fa.fa-buysellads { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-connectdevelop { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-dashcube { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-forumbee { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-leanpub { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-sellsy { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-shirtsinbulk { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-simplybuilt { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-skyatlas { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-diamond { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-diamond:before { + content: "\f3a5"; } + +.fa.fa-intersex:before { + content: "\f224"; } + +.fa.fa-facebook-official { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-facebook-official:before { + content: "\f09a"; } + +.fa.fa-pinterest-p { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-whatsapp { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-hotel:before { + content: "\f236"; } + +.fa.fa-viacoin { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-medium { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-yc { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-yc:before { + content: "\f23b"; } + +.fa.fa-optin-monster { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-opencart { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-expeditedssl { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-battery-4:before { + content: "\f240"; } + +.fa.fa-battery:before { + content: "\f240"; } + +.fa.fa-battery-3:before { + content: "\f241"; } + +.fa.fa-battery-2:before { + content: "\f242"; } + +.fa.fa-battery-1:before { + content: "\f243"; } + +.fa.fa-battery-0:before { + content: "\f244"; } + +.fa.fa-object-group { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-object-ungroup { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o:before { + content: "\f249"; } + +.fa.fa-cc-jcb { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cc-diners-club { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-clone { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hourglass-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hourglass-o:before { + content: "\f254"; } + +.fa.fa-hourglass-1:before { + content: "\f251"; } + +.fa.fa-hourglass-2:before { + content: "\f252"; } + +.fa.fa-hourglass-3:before { + content: "\f253"; } + +.fa.fa-hand-rock-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-rock-o:before { + content: "\f255"; } + +.fa.fa-hand-grab-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-grab-o:before { + content: "\f255"; } + +.fa.fa-hand-paper-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-paper-o:before { + content: "\f256"; } + +.fa.fa-hand-stop-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-stop-o:before { + content: "\f256"; } + +.fa.fa-hand-scissors-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-scissors-o:before { + content: "\f257"; } + +.fa.fa-hand-lizard-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-lizard-o:before { + content: "\f258"; } + +.fa.fa-hand-spock-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-spock-o:before { + content: "\f259"; } + +.fa.fa-hand-pointer-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-pointer-o:before { + content: "\f25a"; } + +.fa.fa-hand-peace-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-hand-peace-o:before { + content: "\f25b"; } + +.fa.fa-registered { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-creative-commons { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gg { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gg-circle { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-tripadvisor { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-get-pocket { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wikipedia-w { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-safari { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-chrome { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-firefox { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-opera { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-internet-explorer { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-television:before { + content: "\f26c"; } + +.fa.fa-contao { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-500px { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-amazon { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-calendar-plus-o:before { + content: "\f271"; } + +.fa.fa-calendar-minus-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-calendar-minus-o:before { + content: "\f272"; } + +.fa.fa-calendar-times-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-calendar-times-o:before { + content: "\f273"; } + +.fa.fa-calendar-check-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-calendar-check-o:before { + content: "\f274"; } + +.fa.fa-map-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-map-o:before { + content: "\f279"; } + +.fa.fa-commenting:before { + content: "\f4ad"; } + +.fa.fa-commenting-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-commenting-o:before { + content: "\f4ad"; } + +.fa.fa-houzz { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-vimeo:before { + content: "\f27d"; } + +.fa.fa-black-tie { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-fonticons { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-reddit-alien { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-edge { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-credit-card-alt:before { + content: "\f09d"; } + +.fa.fa-codiepie { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-modx { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-fort-awesome { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-usb { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-product-hunt { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-mixcloud { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-scribd { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-pause-circle-o:before { + content: "\f28b"; } + +.fa.fa-stop-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-stop-circle-o:before { + content: "\f28d"; } + +.fa.fa-bluetooth { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-bluetooth-b { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-gitlab { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wpbeginner { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wpforms { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-envira { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt:before { + content: "\f368"; } + +.fa.fa-question-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-question-circle-o:before { + content: "\f059"; } + +.fa.fa-volume-control-phone:before { + content: "\f2a0"; } + +.fa.fa-asl-interpreting:before { + content: "\f2a3"; } + +.fa.fa-deafness:before { + content: "\f2a4"; } + +.fa.fa-hard-of-hearing:before { + content: "\f2a4"; } + +.fa.fa-glide { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-glide-g { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-signing:before { + content: "\f2a7"; } + +.fa.fa-viadeo { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-snapchat { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-square { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-first-order { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-yoast { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-themeisle { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official:before { + content: "\f2b3"; } + +.fa.fa-google-plus-circle { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-circle:before { + content: "\f2b3"; } + +.fa.fa-font-awesome { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-fa { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-fa:before { + content: "\f2b4"; } + +.fa.fa-handshake-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-handshake-o:before { + content: "\f2b5"; } + +.fa.fa-envelope-open-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-envelope-open-o:before { + content: "\f2b6"; } + +.fa.fa-linode { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-address-book-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-address-book-o:before { + content: "\f2b9"; } + +.fa.fa-vcard:before { + content: "\f2bb"; } + +.fa.fa-address-card-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-address-card-o:before { + content: "\f2bb"; } + +.fa.fa-vcard-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-vcard-o:before { + content: "\f2bb"; } + +.fa.fa-user-circle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-user-circle-o:before { + content: "\f2bd"; } + +.fa.fa-user-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-user-o:before { + content: "\f007"; } + +.fa.fa-id-badge { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-drivers-license:before { + content: "\f2c2"; } + +.fa.fa-id-card-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-id-card-o:before { + content: "\f2c2"; } + +.fa.fa-drivers-license-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-drivers-license-o:before { + content: "\f2c2"; } + +.fa.fa-quora { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-free-code-camp { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-telegram { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-thermometer-4:before { + content: "\f2c7"; } + +.fa.fa-thermometer:before { + content: "\f2c7"; } + +.fa.fa-thermometer-3:before { + content: "\f2c8"; } + +.fa.fa-thermometer-2:before { + content: "\f2c9"; } + +.fa.fa-thermometer-1:before { + content: "\f2ca"; } + +.fa.fa-thermometer-0:before { + content: "\f2cb"; } + +.fa.fa-bathtub:before { + content: "\f2cd"; } + +.fa.fa-s15:before { + content: "\f2cd"; } + +.fa.fa-window-maximize { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-window-restore { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle:before { + content: "\f410"; } + +.fa.fa-window-close-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-window-close-o:before { + content: "\f410"; } + +.fa.fa-times-rectangle-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle-o:before { + content: "\f410"; } + +.fa.fa-bandcamp { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-grav { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-etsy { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-imdb { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-ravelry { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-eercast:before { + content: "\f2da"; } + +.fa.fa-snowflake-o { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + +.fa.fa-snowflake-o:before { + content: "\f2dc"; } + +.fa.fa-superpowers { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-wpexplorer { + font-family: 'Font Awesome 5 Brands'; + font-weight: 400; } + +.fa.fa-cab:before { + content: "\f1ba"; } diff --git a/templates/map/client/libs/fontawesome/5.12.0/css/v4-shims.min.css b/templates/map/client/libs/fontawesome/5.12.0/css/v4-shims.min.css new file mode 100644 index 00000000..e056e318 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/css/v4-shims.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.12.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa.fa-glass:before{content:"\f000"}.fa.fa-meetup{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-star-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-file-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-pencil:before{content:"\f303"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-share-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-expand:before{content:"\f424"}.fa.fa-compress:before{content:"\f422"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart:before{content:"\f080"}.fa.fa-bar-chart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart-o:before{content:"\f080"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-scissors:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f3fd"}.fa.fa-comment-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard,.fa.fa-paste{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paste:before{content:"\f328"}.fa.fa-lightbulb-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f381"}.fa.fa-cloud-upload:before{content:"\f382"}.fa.fa-bell-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f089"}.fa.fa-star-half-empty{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f089"}.fa.fa-star-half-full{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f089"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before{content:"\f127"}.fa.fa-shield:before{content:"\f3ed"}.fa.fa-calendar-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ticket:before{content:"\f3ff"}.fa.fa-minus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\f155"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\f156"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f881"}.fa.fa-sort-amount-asc:before{content:"\f160"}.fa.fa-sort-amount-desc:before{content:"\f884"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f886"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\f195"}.fa.fa-plus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-spoon:before{content:"\f2e5"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-envelope-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-deviantart,.fa.fa-soundcloud,.fa.fa-spotify{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-bouy:before{content:"\f1cd"}.fa.fa-life-buoy{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-buoy:before{content:"\f1cd"}.fa.fa-life-saver{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-saver:before{content:"\f1cd"}.fa.fa-support{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-sliders:before{content:"\f1de"}.fa.fa-futbol-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-meanpath{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-meanpath:before{content:"\f2b4"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before{content:"\f224"}.fa.fa-facebook-official{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cab:before{content:"\f1ba"} \ No newline at end of file diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.eot b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.eot new file mode 100644 index 00000000..baf40576 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.eot differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.svg b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.svg new file mode 100644 index 00000000..843c1c78 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.svg @@ -0,0 +1,3535 @@ + + + + + +Created by FontForge 20190801 at Tue Dec 10 16:09:21 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.ttf b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.ttf new file mode 100644 index 00000000..99163287 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.ttf differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.woff b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.woff new file mode 100644 index 00000000..f9e3bcd0 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.woff differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.woff2 b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.woff2 new file mode 100644 index 00000000..51c07aef Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-brands-400.woff2 differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.eot b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.eot new file mode 100644 index 00000000..04e25cba Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.eot differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.svg b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.svg new file mode 100644 index 00000000..f1f7e6cb --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Tue Dec 10 16:09:21 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.ttf b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.ttf new file mode 100644 index 00000000..9c6249c0 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.ttf differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.woff b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.woff new file mode 100644 index 00000000..2873e438 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.woff differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.woff2 b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.woff2 new file mode 100644 index 00000000..a34bd652 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-regular-400.woff2 differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.eot b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.eot new file mode 100644 index 00000000..39716a7b Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.eot differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.svg b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.svg new file mode 100644 index 00000000..cfd0e2f4 --- /dev/null +++ b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.svg @@ -0,0 +1,4700 @@ + + + + + +Created by FontForge 20190801 at Tue Dec 10 16:09:21 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.ttf b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.ttf new file mode 100644 index 00000000..ac4baa21 Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.ttf differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.woff b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.woff new file mode 100644 index 00000000..23002f8a Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.woff differ diff --git a/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.woff2 b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.woff2 new file mode 100644 index 00000000..b37f209d Binary files /dev/null and b/templates/map/client/libs/fontawesome/5.12.0/webfonts/fa-solid-900.woff2 differ diff --git a/templates/map/client/libs/gifjs/0.2.0/gif.js b/templates/map/client/libs/gifjs/0.2.0/gif.js new file mode 100644 index 00000000..2e4d2042 --- /dev/null +++ b/templates/map/client/libs/gifjs/0.2.0/gif.js @@ -0,0 +1,3 @@ +// gif.js 0.2.0 - https://github.com/jnordberg/gif.js +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.GIF=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0&&this._events[type].length>m){this._events[type].warned=true;console.error("(node) warning: possible EventEmitter memory "+"leak detected. %d listeners added. "+"Use emitter.setMaxListeners() to increase limit.",this._events[type].length);if(typeof console.trace==="function"){console.trace()}}}return this};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(type,listener){if(!isFunction(listener))throw TypeError("listener must be a function");var fired=false;function g(){this.removeListener(type,g);if(!fired){fired=true;listener.apply(this,arguments)}}g.listener=listener;this.on(type,g);return this};EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events||!this._events[type])return this;list=this._events[type];length=list.length;position=-1;if(list===listener||isFunction(list.listener)&&list.listener===listener){delete this._events[type];if(this._events.removeListener)this.emit("removeListener",type,listener)}else if(isObject(list)){for(i=length;i-- >0;){if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}}if(position<0)return this;if(list.length===1){list.length=0;delete this._events[type]}else{list.splice(position,1)}if(this._events.removeListener)this.emit("removeListener",type,listener)}return this};EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[type])delete this._events[type];return this}if(arguments.length===0){for(key in this._events){if(key==="removeListener")continue;this.removeAllListeners(key)}this.removeAllListeners("removeListener");this._events={};return this}listeners=this._events[type];if(isFunction(listeners)){this.removeListener(type,listeners)}else if(listeners){while(listeners.length)this.removeListener(type,listeners[listeners.length-1])}delete this._events[type];return this};EventEmitter.prototype.listeners=function(type){var ret;if(!this._events||!this._events[type])ret=[];else if(isFunction(this._events[type]))ret=[this._events[type]];else ret=this._events[type].slice();return ret};EventEmitter.prototype.listenerCount=function(type){if(this._events){var evlistener=this._events[type];if(isFunction(evlistener))return 1;else if(evlistener)return evlistener.length}return 0};EventEmitter.listenerCount=function(emitter,type){return emitter.listenerCount(type)};function isFunction(arg){return typeof arg==="function"}function isNumber(arg){return typeof arg==="number"}function isObject(arg){return typeof arg==="object"&&arg!==null}function isUndefined(arg){return arg===void 0}},{}],2:[function(require,module,exports){var UA,browser,mode,platform,ua;ua=navigator.userAgent.toLowerCase();platform=navigator.platform.toLowerCase();UA=ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0];mode=UA[1]==="ie"&&document.documentMode;browser={name:UA[1]==="version"?UA[3]:UA[1],version:mode||parseFloat(UA[1]==="opera"&&UA[4]?UA[4]:UA[2]),platform:{name:ua.match(/ip(?:ad|od|hone)/)?"ios":(ua.match(/(?:webos|android)/)||platform.match(/mac|win|linux/)||["other"])[0]}};browser[browser.name]=true;browser[browser.name+parseInt(browser.version,10)]=true;browser.platform[browser.platform.name]=true;module.exports=browser},{}],3:[function(require,module,exports){var EventEmitter,GIF,browser,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;iref;i=0<=ref?++j:--j){results.push(null)}return results}.call(this);numWorkers=this.spawnWorkers();if(this.options.globalPalette===true){this.renderNextFrame()}else{for(i=j=0,ref=numWorkers;0<=ref?jref;i=0<=ref?++j:--j){this.renderNextFrame()}}this.emit("start");return this.emit("progress",0)};GIF.prototype.abort=function(){var worker;while(true){worker=this.activeWorkers.shift();if(worker==null){break}this.log("killing active worker");worker.terminate()}this.running=false;return this.emit("abort")};GIF.prototype.spawnWorkers=function(){var j,numWorkers,ref,results;numWorkers=Math.min(this.options.workers,this.frames.length);(function(){results=[];for(var j=ref=this.freeWorkers.length;ref<=numWorkers?jnumWorkers;ref<=numWorkers?j++:j--){results.push(j)}return results}).apply(this).forEach(function(_this){return function(i){var worker;_this.log("spawning worker "+i);worker=new Worker(_this.options.workerScript);worker.onmessage=function(event){_this.activeWorkers.splice(_this.activeWorkers.indexOf(worker),1);_this.freeWorkers.push(worker);return _this.frameFinished(event.data)};return _this.freeWorkers.push(worker)}}(this));return numWorkers};GIF.prototype.frameFinished=function(frame){var i,j,ref;this.log("frame "+frame.index+" finished - "+this.activeWorkers.length+" active");this.finishedFrames++;this.emit("progress",this.finishedFrames/this.frames.length);this.imageParts[frame.index]=frame;if(this.options.globalPalette===true){this.options.globalPalette=frame.globalPalette;this.log("global palette analyzed");if(this.frames.length>2){for(i=j=1,ref=this.freeWorkers.length;1<=ref?jref;i=1<=ref?++j:--j){this.renderNextFrame()}}}if(indexOf.call(this.imageParts,null)>=0){return this.renderNextFrame()}else{return this.finishRendering()}};GIF.prototype.finishRendering=function(){var data,frame,i,image,j,k,l,len,len1,len2,len3,offset,page,ref,ref1,ref2;len=0;ref=this.imageParts;for(j=0,len1=ref.length;j=this.frames.length){return}frame=this.frames[this.nextFrame++];worker=this.freeWorkers.shift();task=this.getTask(frame);this.log("starting frame "+(task.index+1)+" of "+this.frames.length);this.activeWorkers.push(worker);return worker.postMessage(task)};GIF.prototype.getContextData=function(ctx){return ctx.getImageData(0,0,this.options.width,this.options.height).data};GIF.prototype.getImageData=function(image){var ctx;if(this._canvas==null){this._canvas=document.createElement("canvas");this._canvas.width=this.options.width;this._canvas.height=this.options.height}ctx=this._canvas.getContext("2d");ctx.setFill=this.options.background;ctx.fillRect(0,0,this.options.width,this.options.height);ctx.drawImage(image,0,0);return this.getContextData(ctx)};GIF.prototype.getTask=function(frame){var index,task;index=this.frames.indexOf(frame);task={index:index,last:index===this.frames.length-1,delay:frame.delay,transparent:frame.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,dither:this.options.dither,globalPalette:this.options.globalPalette,repeat:this.options.repeat,canTransfer:browser.name==="chrome"};if(frame.data!=null){task.data=frame.data}else if(frame.context!=null){task.data=this.getContextData(frame.context)}else if(frame.image!=null){task.data=this.getImageData(frame.image)}else{throw new Error("Invalid frame")}return task};GIF.prototype.log=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];if(!this.options.debug){return}return console.log.apply(console,args)};return GIF}(EventEmitter);module.exports=GIF},{"./browser.coffee":2,events:1}]},{},[3])(3)}); +//# sourceMappingURL=gif.js.map diff --git a/templates/map/client/libs/gifjs/0.2.0/gif.js.map b/templates/map/client/libs/gifjs/0.2.0/gif.js.map new file mode 100644 index 00000000..c9059f95 --- /dev/null +++ b/templates/map/client/libs/gifjs/0.2.0/gif.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","node_modules/events/events.js","src/browser.coffee","src/gif.coffee"],"names":["f","exports","module","define","amd","g","window","global","self","this","GIF","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length","1","EventEmitter","_events","_maxListeners","undefined","prototype","defaultMaxListeners","setMaxListeners","isNumber","isNaN","TypeError","emit","type","er","handler","len","args","listeners","error","isObject","arguments","err","context","isUndefined","isFunction","Array","slice","apply","addListener","listener","m","newListener","push","warned","console","trace","on","once","fired","removeListener","list","position","splice","removeAllListeners","key","ret","listenerCount","evlistener","emitter","arg","UA","browser","mode","platform","ua","navigator","userAgent","toLowerCase","match","document","documentMode","name","version","parseFloat","parseInt","extend","child","parent","hasProp","ctor","constructor","__super__","superClass","defaults","frameDefaults","workerScript","workers","repeat","background","quality","width","height","transparent","debug","dither","delay","copy","options","base","value","running","frames","freeWorkers","activeWorkers","setOptions","setOption","_canvas","results","addFrame","image","frame","ImageData","data","CanvasRenderingContext2D","WebGLRenderingContext","getContextData","childNodes","getImageData","render","j","numWorkers","ref","nextFrame","finishedFrames","imageParts","spawnWorkers","globalPalette","renderNextFrame","abort","worker","shift","log","terminate","Math","min","forEach","_this","Worker","onmessage","event","indexOf","frameFinished","index","finishRendering","k","len1","len2","len3","offset","page","ref1","ref2","pageSize","cursor","round","Uint8Array","set","Blob","task","getTask","postMessage","ctx","createElement","getContext","setFill","fillRect","drawImage","last","canTransfer"],"mappings":";CAAA,SAAAA,GAAA,SAAAC,WAAA,gBAAAC,UAAA,YAAA,CAAAA,OAAAD,QAAAD,QAAA,UAAAG,UAAA,YAAAA,OAAAC,IAAA,CAAAD,UAAAH,OAAA,CAAA,GAAAK,EAAA,UAAAC,UAAA,YAAA,CAAAD,EAAAC,WAAA,UAAAC,UAAA,YAAA,CAAAF,EAAAE,WAAA,UAAAC,QAAA,YAAA,CAAAH,EAAAG,SAAA,CAAAH,EAAAI,KAAAJ,EAAAK,IAAAV,OAAA,WAAA,GAAAG,QAAAD,OAAAD,OAAA,OAAA,SAAAU,GAAAC,EAAAC,EAAAC,GAAA,QAAAC,GAAAC,EAAAC,GAAA,IAAAJ,EAAAG,GAAA,CAAA,IAAAJ,EAAAI,GAAA,CAAA,GAAAE,SAAAC,UAAA,YAAAA,OAAA,KAAAF,GAAAC,EAAA,MAAAA,GAAAF,GAAA,EAAA,IAAAI,EAAA,MAAAA,GAAAJ,GAAA,EAAA,IAAAhB,GAAA,GAAAqB,OAAA,uBAAAL,EAAA,IAAA,MAAAhB,GAAAsB,KAAA,mBAAAtB,EAAA,GAAAuB,GAAAV,EAAAG,IAAAf,WAAAW,GAAAI,GAAA,GAAAQ,KAAAD,EAAAtB,QAAA,SAAAU,GAAA,GAAAE,GAAAD,EAAAI,GAAA,GAAAL,EAAA,OAAAI,GAAAF,EAAAA,EAAAF,IAAAY,EAAAA,EAAAtB,QAAAU,EAAAC,EAAAC,EAAAC,GAAA,MAAAD,GAAAG,GAAAf,QAAA,GAAAmB,SAAAD,UAAA,YAAAA,OAAA,KAAA,GAAAH,GAAA,EAAAA,EAAAF,EAAAW,OAAAT,IAAAD,EAAAD,EAAAE,GAAA,OAAAD,KAAAW,GAAA,SAAAP,QAAAjB,OAAAD,SCqBA,QAAA0B,gBACAlB,KAAAmB,QAAAnB,KAAAmB,WACAnB,MAAAoB,cAAApB,KAAAoB,eAAAC,UAEA5B,OAAAD,QAAA0B,YAGAA,cAAAA,aAAAA,YAEAA,cAAAI,UAAAH,QAAAE,SACAH,cAAAI,UAAAF,cAAAC,SAIAH,cAAAK,oBAAA,EAIAL,cAAAI,UAAAE,gBAAA,SAAApB,GACA,IAAAqB,SAAArB,IAAAA,EAAA,GAAAsB,MAAAtB,GACA,KAAAuB,WAAA,8BACA3B,MAAAoB,cAAAhB,CACA,OAAAJ,MAGAkB,cAAAI,UAAAM,KAAA,SAAAC,MACA,GAAAC,IAAAC,QAAAC,IAAAC,KAAAtB,EAAAuB,SAEA,KAAAlC,KAAAmB,QACAnB,KAAAmB,UAGA,IAAAU,OAAA,QAAA,CACA,IAAA7B,KAAAmB,QAAAgB,OACAC,SAAApC,KAAAmB,QAAAgB,SAAAnC,KAAAmB,QAAAgB,MAAAnB,OAAA,CACAc,GAAAO,UAAA,EACA,IAAAP,aAAAlB,OAAA,CACA,KAAAkB,QACA,CAEA,GAAAQ,KAAA,GAAA1B,OAAA,yCAAAkB,GAAA,IACAQ,KAAAC,QAAAT,EACA,MAAAQ,OAKAP,QAAA/B,KAAAmB,QAAAU,KAEA,IAAAW,YAAAT,SACA,MAAA,MAEA,IAAAU,WAAAV,SAAA,CACA,OAAAM,UAAArB,QAEA,IAAA,GACAe,QAAAhB,KAAAf,KACA,MACA,KAAA,GACA+B,QAAAhB,KAAAf,KAAAqC,UAAA,GACA,MACA,KAAA,GACAN,QAAAhB,KAAAf,KAAAqC,UAAA,GAAAA,UAAA,GACA,MAEA,SACAJ,KAAAS,MAAApB,UAAAqB,MAAA5B,KAAAsB,UAAA,EACAN,SAAAa,MAAA5C,KAAAiC,WAEA,IAAAG,SAAAL,SAAA,CACAE,KAAAS,MAAApB,UAAAqB,MAAA5B,KAAAsB,UAAA,EACAH,WAAAH,QAAAY,OACAX,KAAAE,UAAAlB,MACA,KAAAL,EAAA,EAAAA,EAAAqB,IAAArB,IACAuB,UAAAvB,GAAAiC,MAAA5C,KAAAiC,MAGA,MAAA,MAGAf,cAAAI,UAAAuB,YAAA,SAAAhB,KAAAiB,UACA,GAAAC,EAEA,KAAAN,WAAAK,UACA,KAAAnB,WAAA,8BAEA,KAAA3B,KAAAmB,QACAnB,KAAAmB,UAIA,IAAAnB,KAAAmB,QAAA6B,YACAhD,KAAA4B,KAAA,cAAAC,KACAY,WAAAK,SAAAA,UACAA,SAAAA,SAAAA,SAEA,KAAA9C,KAAAmB,QAAAU,MAEA7B,KAAAmB,QAAAU,MAAAiB,aACA,IAAAV,SAAApC,KAAAmB,QAAAU,OAEA7B,KAAAmB,QAAAU,MAAAoB,KAAAH,cAGA9C,MAAAmB,QAAAU,OAAA7B,KAAAmB,QAAAU,MAAAiB,SAGA,IAAAV,SAAApC,KAAAmB,QAAAU,SAAA7B,KAAAmB,QAAAU,MAAAqB,OAAA,CACA,IAAAV,YAAAxC,KAAAoB,eAAA,CACA2B,EAAA/C,KAAAoB,kBACA,CACA2B,EAAA7B,aAAAK,oBAGA,GAAAwB,GAAAA,EAAA,GAAA/C,KAAAmB,QAAAU,MAAAb,OAAA+B,EAAA,CACA/C,KAAAmB,QAAAU,MAAAqB,OAAA,IACAC,SAAAhB,MAAA,gDACA,sCACA,mDACAnC,KAAAmB,QAAAU,MAAAb,OACA,UAAAmC,SAAAC,QAAA,WAAA,CAEAD,QAAAC,UAKA,MAAApD,MAGAkB,cAAAI,UAAA+B,GAAAnC,aAAAI,UAAAuB,WAEA3B,cAAAI,UAAAgC,KAAA,SAAAzB,KAAAiB,UACA,IAAAL,WAAAK,UACA,KAAAnB,WAAA,8BAEA,IAAA4B,OAAA,KAEA,SAAA3D,KACAI,KAAAwD,eAAA3B,KAAAjC,EAEA,KAAA2D,MAAA,CACAA,MAAA,IACAT,UAAAF,MAAA5C,KAAAqC,YAIAzC,EAAAkD,SAAAA,QACA9C,MAAAqD,GAAAxB,KAAAjC,EAEA,OAAAI,MAIAkB,cAAAI,UAAAkC,eAAA,SAAA3B,KAAAiB,UACA,GAAAW,MAAAC,SAAA1C,OAAAL,CAEA,KAAA8B,WAAAK,UACA,KAAAnB,WAAA,8BAEA,KAAA3B,KAAAmB,UAAAnB,KAAAmB,QAAAU,MACA,MAAA7B,KAEAyD,MAAAzD,KAAAmB,QAAAU,KACAb,QAAAyC,KAAAzC,MACA0C,WAAA,CAEA,IAAAD,OAAAX,UACAL,WAAAgB,KAAAX,WAAAW,KAAAX,WAAAA,SAAA,OACA9C,MAAAmB,QAAAU,KACA,IAAA7B,KAAAmB,QAAAqC,eACAxD,KAAA4B,KAAA,iBAAAC,KAAAiB,cAEA,IAAAV,SAAAqB,MAAA,CACA,IAAA9C,EAAAK,OAAAL,KAAA,GAAA,CACA,GAAA8C,KAAA9C,KAAAmC,UACAW,KAAA9C,GAAAmC,UAAAW,KAAA9C,GAAAmC,WAAAA,SAAA,CACAY,SAAA/C,CACA,QAIA,GAAA+C,SAAA,EACA,MAAA1D,KAEA,IAAAyD,KAAAzC,SAAA,EAAA,CACAyC,KAAAzC,OAAA,QACAhB,MAAAmB,QAAAU,UACA,CACA4B,KAAAE,OAAAD,SAAA,GAGA,GAAA1D,KAAAmB,QAAAqC,eACAxD,KAAA4B,KAAA,iBAAAC,KAAAiB,UAGA,MAAA9C,MAGAkB,cAAAI,UAAAsC,mBAAA,SAAA/B,MACA,GAAAgC,KAAA3B,SAEA,KAAAlC,KAAAmB,QACA,MAAAnB,KAGA,KAAAA,KAAAmB,QAAAqC,eAAA,CACA,GAAAnB,UAAArB,SAAA,EACAhB,KAAAmB,eACA,IAAAnB,KAAAmB,QAAAU,YACA7B,MAAAmB,QAAAU,KACA,OAAA7B,MAIA,GAAAqC,UAAArB,SAAA,EAAA,CACA,IAAA6C,MAAA7D,MAAAmB,QAAA,CACA,GAAA0C,MAAA,iBAAA,QACA7D,MAAA4D,mBAAAC,KAEA7D,KAAA4D,mBAAA,iBACA5D,MAAAmB,UACA,OAAAnB,MAGAkC,UAAAlC,KAAAmB,QAAAU,KAEA,IAAAY,WAAAP,WAAA,CACAlC,KAAAwD,eAAA3B,KAAAK,eACA,IAAAA,UAAA,CAEA,MAAAA,UAAAlB,OACAhB,KAAAwD,eAAA3B,KAAAK,UAAAA,UAAAlB,OAAA,UAEAhB,MAAAmB,QAAAU,KAEA,OAAA7B,MAGAkB,cAAAI,UAAAY,UAAA,SAAAL,MACA,GAAAiC,IACA,KAAA9D,KAAAmB,UAAAnB,KAAAmB,QAAAU,MACAiC,WACA,IAAArB,WAAAzC,KAAAmB,QAAAU,OACAiC,KAAA9D,KAAAmB,QAAAU,WAEAiC,KAAA9D,KAAAmB,QAAAU,MAAAc,OACA,OAAAmB,KAGA5C,cAAAI,UAAAyC,cAAA,SAAAlC,MACA,GAAA7B,KAAAmB,QAAA,CACA,GAAA6C,YAAAhE,KAAAmB,QAAAU,KAEA,IAAAY,WAAAuB,YACA,MAAA,OACA,IAAAA,WACA,MAAAA,YAAAhD,OAEA,MAAA,GAGAE,cAAA6C,cAAA,SAAAE,QAAApC,MACA,MAAAoC,SAAAF,cAAAlC,MAGA,SAAAY,YAAAyB,KACA,aAAAA,OAAA,WAGA,QAAAzC,UAAAyC,KACA,aAAAA,OAAA,SAGA,QAAA9B,UAAA8B,KACA,aAAAA,OAAA,UAAAA,MAAA,KAGA,QAAA1B,aAAA0B,KACA,MAAAA,WAAA,6CC5SA,GAAAC,IAAAC,QAAAC,KAAAC,SAAAC,EAEAA,IAAKC,UAAUC,UAAUC,aACzBJ,UAAWE,UAAUF,SAASI,aAC9BP,IAAKI,GAAGI,MAAM,iGAAmG,KAAM,UAAW,EAClIN,MAAOF,GAAG,KAAM,MAAQS,SAASC,YAEjCT,UACEU,KAASX,GAAG,KAAM,UAAeA,GAAG,GAAQA,GAAG,GAC/CY,QAASV,MAAQW,WAAcb,GAAG,KAAM,SAAWA,GAAG,GAAQA,GAAG,GAAQA,GAAG,IAE5EG,UACEQ,KAASP,GAAGI,MAAM,oBAAyB,OAAYJ,GAAGI,MAAM,sBAAwBL,SAASK,MAAM,mBAAqB,UAAU,IAE1IP,SAAQA,QAAQU,MAAQ,IACxBV,SAAQA,QAAQU,KAAOG,SAASb,QAAQW,QAAS,KAAO,IACxDX,SAAQE,SAASF,QAAQE,SAASQ,MAAQ,IAE1CrF,QAAOD,QAAU4E,iDClBjB,GAAAlD,cAAAjB,IAAAmE,QAAAc,OAAA,SAAAC,MAAAC,QAAA,IAAA,GAAAvB,OAAAuB,QAAA,CAAA,GAAAC,QAAAtE,KAAAqE,OAAAvB,KAAAsB,MAAAtB,KAAAuB,OAAAvB,KAAA,QAAAyB,QAAAtF,KAAAuF,YAAAJ,MAAAG,KAAAhE,UAAA8D,OAAA9D,SAAA6D,OAAA7D,UAAA,GAAAgE,KAAAH,OAAAK,UAAAJ,OAAA9D,SAAA,OAAA6D,sKAACjE,cAAgBR,QAAQ,UAARQ,YACjBkD,SAAU1D,QAAQ,mBAEZT,KAAA,SAAAwF,YAEJ,GAAAC,UAAAC,oCAAAD,WACEE,aAAc,gBACdC,QAAS,EACTC,OAAQ,EACRC,WAAY,OACZC,QAAS,GACTC,MAAO,KACPC,OAAQ,KACRC,YAAa,KACbC,MAAO,MACPC,OAAQ,MAEVV,gBACEW,MAAO,IACPC,KAAM,MAEK,SAAAtG,KAACuG,SACZ,GAAAC,MAAA5C,IAAA6C,KAAA1G,MAAC2G,QAAU,KAEX3G,MAACwG,UACDxG,MAAC4G,SAED5G,MAAC6G,cACD7G,MAAC8G,gBAED9G,MAAC+G,WAAWP,QACZ,KAAA3C,MAAA6B,UAAA,6DACW7B,KAAQ6C,sBAErBM,UAAW,SAACnD,IAAK6C,OACf1G,KAACwG,QAAQ3C,KAAO6C,KAChB,IAAG1G,KAAAiH,SAAA,OAAcpD,MAAQ,SAARA,MAAiB,UAAlC,OACE7D,MAACiH,QAAQpD,KAAO6C,sBAEpBK,WAAY,SAACP,SACX,GAAA3C,KAAAqD,QAAAR,KAAAQ,gBAAArD,MAAA2C,SAAA,wEAAAxG,KAACgH,UAAUnD,IAAK6C,sCAElBS,SAAU,SAACC,MAAOZ,SAChB,GAAAa,OAAAxD,sBADgB2C,WAChBa,QACAA,OAAMlB,YAAcnG,KAACwG,QAAQL,WAC7B,KAAAtC,MAAA8B,eAAA,CACE0B,MAAMxD,KAAO2C,QAAQ3C,MAAQ8B,cAAc9B,KAG7C,GAAuC7D,KAAAwG,QAAAP,OAAA,KAAvC,CAAAjG,KAACgH,UAAU,QAASI,MAAMnB,OAC1B,GAAyCjG,KAAAwG,QAAAN,QAAA,KAAzC,CAAAlG,KAACgH,UAAU,SAAUI,MAAMlB,QAE3B,SAAGoB,aAAA,aAAAA,YAAA,MAAeF,gBAAiBE,WAAnC,CACGD,MAAME,KAAOH,MAAMG,SACjB,UAAIC,4BAAA,aAAAA,2BAAA,MAA8BJ,gBAAiBI,iCAA8BC,yBAAA,aAAAA,wBAAA,MAA2BL,gBAAiBK,uBAA7H,CACH,GAAGjB,QAAQD,KAAX,CACEc,MAAME,KAAOvH,KAAC0H,eAAeN,WAD/B,CAGEC,MAAM9E,QAAU6E,WACf,IAAGA,MAAAO,YAAA,KAAH,CACH,GAAGnB,QAAQD,KAAX,CACEc,MAAME,KAAOvH,KAAC4H,aAAaR,WAD7B,CAGEC,MAAMD,MAAQA,WAJb,CAMH,KAAU,IAAAxG,OAAM,uBAElBZ,MAAC4G,OAAO3D,KAAKoE,sBAEfQ,OAAQ,WACN,GAAAlH,GAAAmH,EAAAC,WAAAC,GAAA,IAAqChI,KAAC2G,QAAtC,CAAA,KAAU,IAAA/F,OAAM,mBAEhB,GAAOZ,KAAAwG,QAAAP,OAAA,MAAuBjG,KAAAwG,QAAAN,QAAA,KAA9B,CACE,KAAU,IAAAtF,OAAM,mDAElBZ,KAAC2G,QAAU,IACX3G,MAACiI,UAAY,CACbjI,MAACkI,eAAiB,CAElBlI,MAACmI,WAAD,4BAAejB,gBAAcvG,EAAAmH,EAAA,EAAAE,IAAAhI,KAAA4G,OAAA5F,OAAA,GAAAgH,IAAAF,EAAAE,IAAAF,EAAAE,IAAArH,EAAA,GAAAqH,MAAAF,IAAAA,EAAd,cAAA,gCACfC,YAAa/H,KAACoI,cAEd,IAAGpI,KAACwG,QAAQ6B,gBAAiB,KAA7B,CACErI,KAACsI,sBADH,CAGE,IAA4B3H,EAAAmH,EAAA,EAAAE,IAAAD,WAAA,GAAAC,IAAAF,EAAAE,IAAAF,EAAAE,IAAArH,EAAA,GAAAqH,MAAAF,IAAAA,EAA5B,CAAA9H,KAACsI,mBAEHtI,KAAC4B,KAAK,eACN5B,MAAC4B,KAAK,WAAY,kBAEpB2G,MAAO,WACL,GAAAC,OAAA,OAAA,KAAA,CACEA,OAASxI,KAAC8G,cAAc2B,OACxB,IAAaD,QAAA,KAAb,CAAA,MACAxI,KAAC0I,IAAI,wBACLF,QAAOG,YACT3I,KAAC2G,QAAU,YACX3G,MAAC4B,KAAK,wBAIRwG,aAAc,WACZ,GAAAN,GAAAC,WAAAC,IAAAd,OAAAa,YAAaa,KAAKC,IAAI7I,KAACwG,QAAQX,QAAS7F,KAAC4G,OAAO5F,SAChD,4KAAmC8H,QAAQ,SAAAC,aAAA,UAACpI,GAC1C,GAAA6H,OAAAO,OAACL,IAAI,mBAAoB/H,EACzB6H,QAAa,GAAAQ,QAAOD,MAACvC,QAAQZ,aAC7B4C,QAAOS,UAAY,SAACC,OAClBH,MAACjC,cAAcnD,OAAOoF,MAACjC,cAAcqC,QAAQX,QAAS,EACtDO,OAAClC,YAAY5D,KAAKuF,cAClBO,OAACK,cAAcF,MAAM3B,aACvBwB,OAAClC,YAAY5D,KAAKuF,UAPuBxI,MAQ3C,OAAO+H,2BAETqB,cAAe,SAAC/B,OACd,GAAA1G,GAAAmH,EAAAE,GAAAhI,MAAC0I,IAAI,SAAUrB,MAAMgC,MAAO,eAAerJ,KAAC8G,cAAc9F,OAAQ,UAClEhB,MAACkI,gBACDlI,MAAC4B,KAAK,WAAY5B,KAACkI,eAAiBlI,KAAC4G,OAAO5F,OAC5ChB,MAACmI,WAAWd,MAAMgC,OAAShC,KAE3B,IAAGrH,KAACwG,QAAQ6B,gBAAiB,KAA7B,CACErI,KAACwG,QAAQ6B,cAAgBhB,MAAMgB,aAC/BrI,MAAC0I,IAAI,0BACL,IAAyD1I,KAAC4G,OAAO5F,OAAS,EAA1E,CAAA,IAA4BL,EAAAmH,EAAA,EAAAE,IAAAhI,KAAA6G,YAAA7F,OAAA,GAAAgH,IAAAF,EAAAE,IAAAF,EAAAE,IAAArH,EAAA,GAAAqH,MAAAF,IAAAA,EAA5B,CAAA9H,KAACsI,oBACH,GAAGa,QAAApI,KAAQf,KAACmI,WAAT,OAAA,EAAH,OACEnI,MAACsI,sBADH,OAGEtI,MAACsJ,kCAELA,gBAAiB,WACf,GAAA/B,MAAAF,MAAA1G,EAAAyG,MAAAU,EAAAyB,EAAAzI,EAAAkB,IAAAwH,KAAAC,KAAAC,KAAAC,OAAAC,KAAA5B,IAAA6B,KAAAC,IAAA9H,KAAM,CACNgG,KAAAhI,KAAAmI,UAAA,KAAAL,EAAA,EAAA0B,KAAAxB,IAAAhH,OAAA8G,EAAA0B,KAAA1B,IAAA,aACE9F,OAAQqF,MAAME,KAAKvG,OAAS,GAAKqG,MAAM0C,SAAW1C,MAAM2C,OAC1DhI,KAAOqF,MAAM0C,SAAW1C,MAAM2C,MAC9BhK,MAAC0I,IAAI,iCAAkCE,KAAKqB,MAAMjI,IAAM,KAAO,KAC/DuF,MAAW,GAAA2C,YAAWlI,IACtB2H,QAAS,CACTE,MAAA7J,KAAAmI,UAAA,KAAAoB,EAAA,EAAAE,KAAAI,KAAA7I,OAAAuI,EAAAE,KAAAF,IAAA,cACEO,MAAAzC,MAAAE,IAAA,KAAA5G,EAAAG,EAAA,EAAA4I,KAAAI,KAAA9I,OAAAF,EAAA4I,KAAA/I,IAAAG,EAAA,aACEyG,MAAK4C,IAAIP,KAAMD,OACf,IAAGhJ,IAAK0G,MAAME,KAAKvG,OAAS,EAA5B,CACE2I,QAAUtC,MAAM2C,WADlB,CAGEL,QAAUtC,MAAM0C,WAEtB3C,MAAY,GAAAgD,OAAM7C,OAChB1F,KAAM,oBAER7B,MAAC4B,KAAK,WAAYwF,MAAOG,qBAE3Be,gBAAiB,WACf,GAAAjB,OAAAgD,KAAA7B,MAAA,IAAqCxI,KAAC6G,YAAY7F,SAAU,EAA5D,CAAA,KAAU,IAAAJ,OAAM,mBAChB,GAAUZ,KAACiI,WAAajI,KAAC4G,OAAO5F,OAAhC,CAAA,OAEAqG,MAAQrH,KAAC4G,OAAO5G,KAACiI,YACjBO,QAASxI,KAAC6G,YAAY4B,OACtB4B,MAAOrK,KAACsK,QAAQjD,MAEhBrH,MAAC0I,IAAI,mBAAmB2B,KAAKhB,MAAQ,GAAG,OAAOrJ,KAAC4G,OAAO5F,OACvDhB,MAAC8G,cAAc7D,KAAKuF,cACpBA,QAAO+B,YAAYF,qBAErB3C,eAAgB,SAAC8C,KACf,MAAOA,KAAI5C,aAAa,EAAG,EAAG5H,KAACwG,QAAQP,MAAOjG,KAACwG,QAAQN,QAAQqB,oBAEjEK,aAAc,SAACR,OACb,GAAAoD,IAAA,IAAOxK,KAAAiH,SAAA,KAAP,CACEjH,KAACiH,QAAUrC,SAAS6F,cAAc,SAClCzK,MAACiH,QAAQhB,MAAQjG,KAACwG,QAAQP,KAC1BjG,MAACiH,QAAQf,OAASlG,KAACwG,QAAQN,OAE7BsE,IAAMxK,KAACiH,QAAQyD,WAAW,KAC1BF,KAAIG,QAAU3K,KAACwG,QAAQT,UACvByE,KAAII,SAAS,EAAG,EAAG5K,KAACwG,QAAQP,MAAOjG,KAACwG,QAAQN,OAC5CsE,KAAIK,UAAUzD,MAAO,EAAG,EAExB,OAAOpH,MAAC0H,eAAe8C,oBAEzBF,QAAS,SAACjD,OACR,GAAAgC,OAAAgB,IAAAhB,OAAQrJ,KAAC4G,OAAOuC,QAAQ9B,MACxBgD,OACEhB,MAAOA,MACPyB,KAAMzB,QAAUrJ,KAAC4G,OAAO5F,OAAS,EACjCsF,MAAOe,MAAMf,MACbH,YAAakB,MAAMlB,YACnBF,MAAOjG,KAACwG,QAAQP,MAChBC,OAAQlG,KAACwG,QAAQN,OACjBF,QAAShG,KAACwG,QAAQR,QAClBK,OAAQrG,KAACwG,QAAQH,OACjBgC,cAAerI,KAACwG,QAAQ6B,cACxBvC,OAAQ9F,KAACwG,QAAQV,OACjBiF,YAAc3G,QAAQU,OAAQ,SAEhC,IAAGuC,MAAAE,MAAA,KAAH,CACE8C,KAAK9C,KAAOF,MAAME,SACf,IAAGF,MAAA9E,SAAA,KAAH,CACH8H,KAAK9C,KAAOvH,KAAC0H,eAAeL,MAAM9E,aAC/B,IAAG8E,MAAAD,OAAA,KAAH,CACHiD,KAAK9C,KAAOvH,KAAC4H,aAAaP,MAAMD,WAD7B,CAGH,KAAU,IAAAxG,OAAM,iBAElB,MAAOyJ,qBAET3B,IAAK,WACH,GAAAzG,KADIA,MAAA,GAAAI,UAAArB,OAAA2B,MAAA5B,KAAAsB,UAAA,KACJ,KAAcrC,KAACwG,QAAQJ,MAAvB,CAAA,aACAjD,SAAQuF,IAAR9F,MAAAO,QAAYlB,mBA1MEf,aA6MlBzB,QAAOD,QAAUS","sourceRoot":"","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 0 && this._events[type].length > m) {\n this._events[type].warned = true;\n console.error('(node) warning: possible EventEmitter memory ' +\n 'leak detected. %d listeners added. ' +\n 'Use emitter.setMaxListeners() to increase limit.',\n this._events[type].length);\n if (typeof console.trace === 'function') {\n // not supported in IE 10\n console.trace();\n }\n }\n }\n\n return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n if (!isFunction(listener))\n throw TypeError('listener must be a function');\n\n var fired = false;\n\n function g() {\n this.removeListener(type, g);\n\n if (!fired) {\n fired = true;\n listener.apply(this, arguments);\n }\n }\n\n g.listener = listener;\n this.on(type, g);\n\n return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n var list, position, length, i;\n\n if (!isFunction(listener))\n throw TypeError('listener must be a function');\n\n if (!this._events || !this._events[type])\n return this;\n\n list = this._events[type];\n length = list.length;\n position = -1;\n\n if (list === listener ||\n (isFunction(list.listener) && list.listener === listener)) {\n delete this._events[type];\n if (this._events.removeListener)\n this.emit('removeListener', type, listener);\n\n } else if (isObject(list)) {\n for (i = length; i-- > 0;) {\n if (list[i] === listener ||\n (list[i].listener && list[i].listener === listener)) {\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (list.length === 1) {\n list.length = 0;\n delete this._events[type];\n } else {\n list.splice(position, 1);\n }\n\n if (this._events.removeListener)\n this.emit('removeListener', type, listener);\n }\n\n return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n var key, listeners;\n\n if (!this._events)\n return this;\n\n // not listening for removeListener, no need to emit\n if (!this._events.removeListener) {\n if (arguments.length === 0)\n this._events = {};\n else if (this._events[type])\n delete this._events[type];\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n for (key in this._events) {\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = {};\n return this;\n }\n\n listeners = this._events[type];\n\n if (isFunction(listeners)) {\n this.removeListener(type, listeners);\n } else if (listeners) {\n // LIFO order\n while (listeners.length)\n this.removeListener(type, listeners[listeners.length - 1]);\n }\n delete this._events[type];\n\n return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n var ret;\n if (!this._events || !this._events[type])\n ret = [];\n else if (isFunction(this._events[type]))\n ret = [this._events[type]];\n else\n ret = this._events[type].slice();\n return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n if (this._events) {\n var evlistener = this._events[type];\n\n if (isFunction(evlistener))\n return 1;\n else if (evlistener)\n return evlistener.length;\n }\n return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n return arg === void 0;\n}\n","### CoffeeScript version of the browser detection from MooTools ###\n\nua = navigator.userAgent.toLowerCase()\nplatform = navigator.platform.toLowerCase()\nUA = ua.match(/(opera|ie|firefox|chrome|version)[\\s\\/:]([\\w\\d\\.]+)?.*?(safari|version[\\s\\/:]([\\w\\d\\.]+)|$)/) or [null, 'unknown', 0]\nmode = UA[1] == 'ie' && document.documentMode\n\nbrowser =\n name: if UA[1] is 'version' then UA[3] else UA[1]\n version: mode or parseFloat(if UA[1] is 'opera' && UA[4] then UA[4] else UA[2])\n\n platform:\n name: if ua.match(/ip(?:ad|od|hone)/) then 'ios' else (ua.match(/(?:webos|android)/) or platform.match(/mac|win|linux/) or ['other'])[0]\n\nbrowser[browser.name] = true\nbrowser[browser.name + parseInt(browser.version, 10)] = true\nbrowser.platform[browser.platform.name] = true\n\nmodule.exports = browser\n","{EventEmitter} = require 'events'\nbrowser = require './browser.coffee'\n\nclass GIF extends EventEmitter\n\n defaults =\n workerScript: 'gif.worker.js'\n workers: 2\n repeat: 0 # repeat forever, -1 = repeat once\n background: '#fff'\n quality: 10 # pixel sample interval, lower is better\n width: null # size derermined from first frame if possible\n height: null\n transparent: null\n debug: false\n dither: false # see GIFEncoder.js for dithering options\n\n frameDefaults =\n delay: 500 # ms\n copy: false\n\n constructor: (options) ->\n @running = false\n\n @options = {}\n @frames = []\n\n @freeWorkers = []\n @activeWorkers = []\n\n @setOptions options\n for key, value of defaults\n @options[key] ?= value\n\n setOption: (key, value) ->\n @options[key] = value\n if @_canvas? and key in ['width', 'height']\n @_canvas[key] = value\n\n setOptions: (options) ->\n @setOption key, value for own key, value of options\n\n addFrame: (image, options={}) ->\n frame = {}\n frame.transparent = @options.transparent\n for key of frameDefaults\n frame[key] = options[key] or frameDefaults[key]\n\n # use the images width and height for options unless already set\n @setOption 'width', image.width unless @options.width?\n @setOption 'height', image.height unless @options.height?\n\n if ImageData? and image instanceof ImageData\n frame.data = image.data\n else if (CanvasRenderingContext2D? and image instanceof CanvasRenderingContext2D) or (WebGLRenderingContext? and image instanceof WebGLRenderingContext)\n if options.copy\n frame.data = @getContextData image\n else\n frame.context = image\n else if image.childNodes?\n if options.copy\n frame.data = @getImageData image\n else\n frame.image = image\n else\n throw new Error 'Invalid image'\n\n @frames.push frame\n\n render: ->\n throw new Error 'Already running' if @running\n\n if not @options.width? or not @options.height?\n throw new Error 'Width and height must be set prior to rendering'\n\n @running = true\n @nextFrame = 0\n @finishedFrames = 0\n\n @imageParts = (null for i in [0...@frames.length])\n numWorkers = @spawnWorkers()\n # we need to wait for the palette\n if @options.globalPalette == true\n @renderNextFrame()\n else\n @renderNextFrame() for i in [0...numWorkers]\n\n @emit 'start'\n @emit 'progress', 0\n\n abort: ->\n loop\n worker = @activeWorkers.shift()\n break unless worker?\n @log 'killing active worker'\n worker.terminate()\n @running = false\n @emit 'abort'\n\n # private\n\n spawnWorkers: ->\n numWorkers = Math.min(@options.workers, @frames.length)\n [@freeWorkers.length...numWorkers].forEach (i) =>\n @log \"spawning worker #{ i }\"\n worker = new Worker @options.workerScript\n worker.onmessage = (event) =>\n @activeWorkers.splice @activeWorkers.indexOf(worker), 1\n @freeWorkers.push worker\n @frameFinished event.data\n @freeWorkers.push worker\n return numWorkers\n\n frameFinished: (frame) ->\n @log \"frame #{ frame.index } finished - #{ @activeWorkers.length } active\"\n @finishedFrames++\n @emit 'progress', @finishedFrames / @frames.length\n @imageParts[frame.index] = frame\n # remember calculated palette, spawn the rest of the workers\n if @options.globalPalette == true\n @options.globalPalette = frame.globalPalette\n @log 'global palette analyzed'\n @renderNextFrame() for i in [1...@freeWorkers.length] if @frames.length > 2\n if null in @imageParts\n @renderNextFrame()\n else\n @finishRendering()\n\n finishRendering: ->\n len = 0\n for frame in @imageParts\n len += (frame.data.length - 1) * frame.pageSize + frame.cursor\n len += frame.pageSize - frame.cursor\n @log \"rendering finished - filesize #{ Math.round(len / 1000) }kb\"\n data = new Uint8Array len\n offset = 0\n for frame in @imageParts\n for page, i in frame.data\n data.set page, offset\n if i is frame.data.length - 1\n offset += frame.cursor\n else\n offset += frame.pageSize\n\n image = new Blob [data],\n type: 'image/gif'\n\n @emit 'finished', image, data\n\n renderNextFrame: ->\n throw new Error 'No free workers' if @freeWorkers.length is 0\n return if @nextFrame >= @frames.length # no new frame to render\n\n frame = @frames[@nextFrame++]\n worker = @freeWorkers.shift()\n task = @getTask frame\n\n @log \"starting frame #{ task.index + 1 } of #{ @frames.length }\"\n @activeWorkers.push worker\n worker.postMessage task#, [task.data.buffer]\n\n getContextData: (ctx) ->\n return ctx.getImageData(0, 0, @options.width, @options.height).data\n\n getImageData: (image) ->\n if not @_canvas?\n @_canvas = document.createElement 'canvas'\n @_canvas.width = @options.width\n @_canvas.height = @options.height\n\n ctx = @_canvas.getContext '2d'\n ctx.setFill = @options.background\n ctx.fillRect 0, 0, @options.width, @options.height\n ctx.drawImage image, 0, 0\n\n return @getContextData ctx\n\n getTask: (frame) ->\n index = @frames.indexOf frame\n task =\n index: index\n last: index is (@frames.length - 1)\n delay: frame.delay\n transparent: frame.transparent\n width: @options.width\n height: @options.height\n quality: @options.quality\n dither: @options.dither\n globalPalette: @options.globalPalette\n repeat: @options.repeat\n canTransfer: (browser.name is 'chrome')\n\n if frame.data?\n task.data = frame.data\n else if frame.context?\n task.data = @getContextData frame.context\n else if frame.image?\n task.data = @getImageData frame.image\n else\n throw new Error 'Invalid frame'\n\n return task\n\n log: (args...) ->\n return unless @options.debug\n console.log args...\n\n\nmodule.exports = GIF\n"]} \ No newline at end of file diff --git a/templates/map/client/libs/gifjs/0.2.0/gif.worker.js b/templates/map/client/libs/gifjs/0.2.0/gif.worker.js new file mode 100644 index 00000000..269624e6 --- /dev/null +++ b/templates/map/client/libs/gifjs/0.2.0/gif.worker.js @@ -0,0 +1,3 @@ +// gif.worker.js 0.2.0 - https://github.com/jnordberg/gif.js +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=ByteArray.pageSize)this.newPage();this.pages[this.page][this.cursor++]=val};ByteArray.prototype.writeUTFBytes=function(string){for(var l=string.length,i=0;i=0)this.dispose=disposalCode};GIFEncoder.prototype.setRepeat=function(repeat){this.repeat=repeat};GIFEncoder.prototype.setTransparent=function(color){this.transparent=color};GIFEncoder.prototype.addFrame=function(imageData){this.image=imageData;this.colorTab=this.globalPalette&&this.globalPalette.slice?this.globalPalette:null;this.getImagePixels();this.analyzePixels();if(this.globalPalette===true)this.globalPalette=this.colorTab;if(this.firstFrame){this.writeLSD();this.writePalette();if(this.repeat>=0){this.writeNetscapeExt()}}this.writeGraphicCtrlExt();this.writeImageDesc();if(!this.firstFrame&&!this.globalPalette)this.writePalette();this.writePixels();this.firstFrame=false};GIFEncoder.prototype.finish=function(){this.out.writeByte(59)};GIFEncoder.prototype.setQuality=function(quality){if(quality<1)quality=1;this.sample=quality};GIFEncoder.prototype.setDither=function(dither){if(dither===true)dither="FloydSteinberg";this.dither=dither};GIFEncoder.prototype.setGlobalPalette=function(palette){this.globalPalette=palette};GIFEncoder.prototype.getGlobalPalette=function(){return this.globalPalette&&this.globalPalette.slice&&this.globalPalette.slice(0)||this.globalPalette};GIFEncoder.prototype.writeHeader=function(){this.out.writeUTFBytes("GIF89a")};GIFEncoder.prototype.analyzePixels=function(){if(!this.colorTab){this.neuQuant=new NeuQuant(this.pixels,this.sample);this.neuQuant.buildColormap();this.colorTab=this.neuQuant.getColormap()}if(this.dither){this.ditherPixels(this.dither.replace("-serpentine",""),this.dither.match(/-serpentine/)!==null)}else{this.indexPixels()}this.pixels=null;this.colorDepth=8;this.palSize=7;if(this.transparent!==null){this.transIndex=this.findClosest(this.transparent,true)}};GIFEncoder.prototype.indexPixels=function(imgq){var nPix=this.pixels.length/3;this.indexedPixels=new Uint8Array(nPix);var k=0;for(var j=0;j=0&&x1+x=0&&y1+y>16,(c&65280)>>8,c&255,used)};GIFEncoder.prototype.findClosestRGB=function(r,g,b,used){if(this.colorTab===null)return-1;if(this.neuQuant&&!used){return this.neuQuant.lookupRGB(r,g,b)}var c=b|g<<8|r<<16;var minpos=0;var dmin=256*256*256;var len=this.colorTab.length;for(var i=0,index=0;i=0){disp=dispose&7}disp<<=2;this.out.writeByte(0|disp|0|transp);this.writeShort(this.delay);this.out.writeByte(this.transIndex);this.out.writeByte(0)};GIFEncoder.prototype.writeImageDesc=function(){this.out.writeByte(44);this.writeShort(0);this.writeShort(0);this.writeShort(this.width);this.writeShort(this.height);if(this.firstFrame||this.globalPalette){this.out.writeByte(0)}else{this.out.writeByte(128|0|0|0|this.palSize)}};GIFEncoder.prototype.writeLSD=function(){this.writeShort(this.width);this.writeShort(this.height);this.out.writeByte(128|112|0|this.palSize);this.out.writeByte(0);this.out.writeByte(0)};GIFEncoder.prototype.writeNetscapeExt=function(){this.out.writeByte(33);this.out.writeByte(255);this.out.writeByte(11);this.out.writeUTFBytes("NETSCAPE2.0");this.out.writeByte(3);this.out.writeByte(1);this.writeShort(this.repeat);this.out.writeByte(0)};GIFEncoder.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var n=3*256-this.colorTab.length;for(var i=0;i>8&255)};GIFEncoder.prototype.writePixels=function(){var enc=new LZWEncoder(this.width,this.height,this.indexedPixels,this.colorDepth);enc.encode(this.out)};GIFEncoder.prototype.stream=function(){return this.out};module.exports=GIFEncoder},{"./LZWEncoder.js":2,"./TypedNeuQuant.js":3}],2:[function(require,module,exports){var EOF=-1;var BITS=12;var HSIZE=5003;var masks=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];function LZWEncoder(width,height,pixels,colorDepth){var initCodeSize=Math.max(2,colorDepth);var accum=new Uint8Array(256);var htab=new Int32Array(HSIZE);var codetab=new Int32Array(HSIZE);var cur_accum,cur_bits=0;var a_count;var free_ent=0;var maxcode;var clear_flg=false;var g_init_bits,ClearCode,EOFCode;function char_out(c,outs){accum[a_count++]=c;if(a_count>=254)flush_char(outs)}function cl_block(outs){cl_hash(HSIZE);free_ent=ClearCode+2;clear_flg=true;output(ClearCode,outs)}function cl_hash(hsize){for(var i=0;i=0){disp=hsize_reg-i;if(i===0)disp=1;do{if((i-=disp)<0)i+=hsize_reg;if(htab[i]===fcode){ent=codetab[i];continue outer_loop}}while(htab[i]>=0)}output(ent,outs);ent=c;if(free_ent<1<0){outs.writeByte(a_count);outs.writeBytes(accum,0,a_count);a_count=0}}function MAXCODE(n_bits){return(1<0)cur_accum|=code<=8){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}if(free_ent>maxcode||clear_flg){if(clear_flg){maxcode=MAXCODE(n_bits=g_init_bits);clear_flg=false}else{++n_bits;if(n_bits==BITS)maxcode=1<0){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}flush_char(outs)}}this.encode=encode}module.exports=LZWEncoder},{}],3:[function(require,module,exports){var ncycles=100;var netsize=256;var maxnetpos=netsize-1;var netbiasshift=4;var intbiasshift=16;var intbias=1<>betashift;var betagamma=intbias<>3;var radiusbiasshift=6;var radiusbias=1<>3);var i,v;for(i=0;i>=netbiasshift;network[i][1]>>=netbiasshift;network[i][2]>>=netbiasshift;network[i][3]=i}}function altersingle(alpha,i,b,g,r){network[i][0]-=alpha*(network[i][0]-b)/initalpha;network[i][1]-=alpha*(network[i][1]-g)/initalpha;network[i][2]-=alpha*(network[i][2]-r)/initalpha}function alterneigh(radius,i,b,g,r){var lo=Math.abs(i-radius);var hi=Math.min(i+radius,netsize);var j=i+1;var k=i-1;var m=1;var p,a;while(jlo){a=radpower[m++];if(jlo){p=network[k--];p[0]-=a*(p[0]-b)/alpharadbias;p[1]-=a*(p[1]-g)/alpharadbias;p[2]-=a*(p[2]-r)/alpharadbias}}}function contest(b,g,r){var bestd=~(1<<31);var bestbiasd=bestd;var bestpos=-1;var bestbiaspos=bestpos;var i,n,dist,biasdist,betafreq;for(i=0;i>intbiasshift-netbiasshift);if(biasdist>betashift;freq[i]-=betafreq;bias[i]+=betafreq<>1;for(j=previouscol+1;j>1;for(j=previouscol+1;j<256;j++)netindex[j]=maxnetpos}function inxsearch(b,g,r){var a,p,dist;var bestd=1e3;var best=-1;var i=netindex[g];var j=i-1;while(i=0){if(i=bestd)i=netsize;else{i++;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist=0){p=network[j];dist=g-p[1];if(dist>=bestd)j=-1;else{j--;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist>radiusbiasshift;if(rad<=1)rad=0;for(i=0;i=lengthcount)pix-=lengthcount;i++;if(delta===0)delta=1;if(i%delta===0){alpha-=alpha/alphadec;radius-=radius/radiusdec;rad=radius>>radiusbiasshift;if(rad<=1)rad=0;for(j=0;j= ByteArray.pageSize) this.newPage();\n this.pages[this.page][this.cursor++] = val;\n};\n\nByteArray.prototype.writeUTFBytes = function(string) {\n for (var l = string.length, i = 0; i < l; i++)\n this.writeByte(string.charCodeAt(i));\n};\n\nByteArray.prototype.writeBytes = function(array, offset, length) {\n for (var l = length || array.length, i = offset || 0; i < l; i++)\n this.writeByte(array[i]);\n};\n\nfunction GIFEncoder(width, height) {\n // image size\n this.width = ~~width;\n this.height = ~~height;\n\n // transparent color if given\n this.transparent = null;\n\n // transparent index in color table\n this.transIndex = 0;\n\n // -1 = no repeat, 0 = forever. anything else is repeat count\n this.repeat = -1;\n\n // frame delay (hundredths)\n this.delay = 0;\n\n this.image = null; // current frame\n this.pixels = null; // BGR byte array from frame\n this.indexedPixels = null; // converted frame indexed to palette\n this.colorDepth = null; // number of bit planes\n this.colorTab = null; // RGB palette\n this.neuQuant = null; // NeuQuant instance that was used to generate this.colorTab.\n this.usedEntry = new Array(); // active palette entries\n this.palSize = 7; // color table size (bits-1)\n this.dispose = -1; // disposal code (-1 = use default)\n this.firstFrame = true;\n this.sample = 10; // default sample interval for quantizer\n this.dither = false; // default dithering\n this.globalPalette = false;\n\n this.out = new ByteArray();\n}\n\n/*\n Sets the delay time between each frame, or changes it for subsequent frames\n (applies to last frame added)\n*/\nGIFEncoder.prototype.setDelay = function(milliseconds) {\n this.delay = Math.round(milliseconds / 10);\n};\n\n/*\n Sets frame rate in frames per second.\n*/\nGIFEncoder.prototype.setFrameRate = function(fps) {\n this.delay = Math.round(100 / fps);\n};\n\n/*\n Sets the GIF frame disposal code for the last added frame and any\n subsequent frames.\n\n Default is 0 if no transparent color has been set, otherwise 2.\n*/\nGIFEncoder.prototype.setDispose = function(disposalCode) {\n if (disposalCode >= 0) this.dispose = disposalCode;\n};\n\n/*\n Sets the number of times the set of GIF frames should be played.\n\n -1 = play once\n 0 = repeat indefinitely\n\n Default is -1\n\n Must be invoked before the first image is added\n*/\n\nGIFEncoder.prototype.setRepeat = function(repeat) {\n this.repeat = repeat;\n};\n\n/*\n Sets the transparent color for the last added frame and any subsequent\n frames. Since all colors are subject to modification in the quantization\n process, the color in the final palette for each frame closest to the given\n color becomes the transparent color for that frame. May be set to null to\n indicate no transparent color.\n*/\nGIFEncoder.prototype.setTransparent = function(color) {\n this.transparent = color;\n};\n\n/*\n Adds next GIF frame. The frame is not written immediately, but is\n actually deferred until the next frame is received so that timing\n data can be inserted. Invoking finish() flushes all frames.\n*/\nGIFEncoder.prototype.addFrame = function(imageData) {\n this.image = imageData;\n\n this.colorTab = this.globalPalette && this.globalPalette.slice ? this.globalPalette : null;\n\n this.getImagePixels(); // convert to correct format if necessary\n this.analyzePixels(); // build color table & map pixels\n\n if (this.globalPalette === true) this.globalPalette = this.colorTab;\n\n if (this.firstFrame) {\n this.writeLSD(); // logical screen descriptior\n this.writePalette(); // global color table\n if (this.repeat >= 0) {\n // use NS app extension to indicate reps\n this.writeNetscapeExt();\n }\n }\n\n this.writeGraphicCtrlExt(); // write graphic control extension\n this.writeImageDesc(); // image descriptor\n if (!this.firstFrame && !this.globalPalette) this.writePalette(); // local color table\n this.writePixels(); // encode and write pixel data\n\n this.firstFrame = false;\n};\n\n/*\n Adds final trailer to the GIF stream, if you don't call the finish method\n the GIF stream will not be valid.\n*/\nGIFEncoder.prototype.finish = function() {\n this.out.writeByte(0x3b); // gif trailer\n};\n\n/*\n Sets quality of color quantization (conversion of images to the maximum 256\n colors allowed by the GIF specification). Lower values (minimum = 1)\n produce better colors, but slow processing significantly. 10 is the\n default, and produces good color mapping at reasonable speeds. Values\n greater than 20 do not yield significant improvements in speed.\n*/\nGIFEncoder.prototype.setQuality = function(quality) {\n if (quality < 1) quality = 1;\n this.sample = quality;\n};\n\n/*\n Sets dithering method. Available are:\n - FALSE no dithering\n - TRUE or FloydSteinberg\n - FalseFloydSteinberg\n - Stucki\n - Atkinson\n You can add '-serpentine' to use serpentine scanning\n*/\nGIFEncoder.prototype.setDither = function(dither) {\n if (dither === true) dither = 'FloydSteinberg';\n this.dither = dither;\n};\n\n/*\n Sets global palette for all frames.\n You can provide TRUE to create global palette from first picture.\n Or an array of r,g,b,r,g,b,...\n*/\nGIFEncoder.prototype.setGlobalPalette = function(palette) {\n this.globalPalette = palette;\n};\n\n/*\n Returns global palette used for all frames.\n If setGlobalPalette(true) was used, then this function will return\n calculated palette after the first frame is added.\n*/\nGIFEncoder.prototype.getGlobalPalette = function() {\n return (this.globalPalette && this.globalPalette.slice && this.globalPalette.slice(0)) || this.globalPalette;\n};\n\n/*\n Writes GIF file header\n*/\nGIFEncoder.prototype.writeHeader = function() {\n this.out.writeUTFBytes(\"GIF89a\");\n};\n\n/*\n Analyzes current frame colors and creates color map.\n*/\nGIFEncoder.prototype.analyzePixels = function() {\n if (!this.colorTab) {\n this.neuQuant = new NeuQuant(this.pixels, this.sample);\n this.neuQuant.buildColormap(); // create reduced palette\n this.colorTab = this.neuQuant.getColormap();\n }\n\n // map image pixels to new palette\n if (this.dither) {\n this.ditherPixels(this.dither.replace('-serpentine', ''), this.dither.match(/-serpentine/) !== null);\n } else {\n this.indexPixels();\n }\n\n this.pixels = null;\n this.colorDepth = 8;\n this.palSize = 7;\n\n // get closest match to transparent color if specified\n if (this.transparent !== null) {\n this.transIndex = this.findClosest(this.transparent, true);\n }\n};\n\n/*\n Index pixels, without dithering\n*/\nGIFEncoder.prototype.indexPixels = function(imgq) {\n var nPix = this.pixels.length / 3;\n this.indexedPixels = new Uint8Array(nPix);\n var k = 0;\n for (var j = 0; j < nPix; j++) {\n var index = this.findClosestRGB(\n this.pixels[k++] & 0xff,\n this.pixels[k++] & 0xff,\n this.pixels[k++] & 0xff\n );\n this.usedEntry[index] = true;\n this.indexedPixels[j] = index;\n }\n};\n\n/*\n Taken from http://jsbin.com/iXofIji/2/edit by PAEz\n*/\nGIFEncoder.prototype.ditherPixels = function(kernel, serpentine) {\n var kernels = {\n FalseFloydSteinberg: [\n [3 / 8, 1, 0],\n [3 / 8, 0, 1],\n [2 / 8, 1, 1]\n ],\n FloydSteinberg: [\n [7 / 16, 1, 0],\n [3 / 16, -1, 1],\n [5 / 16, 0, 1],\n [1 / 16, 1, 1]\n ],\n Stucki: [\n [8 / 42, 1, 0],\n [4 / 42, 2, 0],\n [2 / 42, -2, 1],\n [4 / 42, -1, 1],\n [8 / 42, 0, 1],\n [4 / 42, 1, 1],\n [2 / 42, 2, 1],\n [1 / 42, -2, 2],\n [2 / 42, -1, 2],\n [4 / 42, 0, 2],\n [2 / 42, 1, 2],\n [1 / 42, 2, 2]\n ],\n Atkinson: [\n [1 / 8, 1, 0],\n [1 / 8, 2, 0],\n [1 / 8, -1, 1],\n [1 / 8, 0, 1],\n [1 / 8, 1, 1],\n [1 / 8, 0, 2]\n ]\n };\n\n if (!kernel || !kernels[kernel]) {\n throw 'Unknown dithering kernel: ' + kernel;\n }\n\n var ds = kernels[kernel];\n var index = 0,\n height = this.height,\n width = this.width,\n data = this.pixels;\n var direction = serpentine ? -1 : 1;\n\n this.indexedPixels = new Uint8Array(this.pixels.length / 3);\n\n for (var y = 0; y < height; y++) {\n\n if (serpentine) direction = direction * -1;\n\n for (var x = (direction == 1 ? 0 : width - 1), xend = (direction == 1 ? width : 0); x !== xend; x += direction) {\n\n index = (y * width) + x;\n // Get original colour\n var idx = index * 3;\n var r1 = data[idx];\n var g1 = data[idx + 1];\n var b1 = data[idx + 2];\n\n // Get converted colour\n idx = this.findClosestRGB(r1, g1, b1);\n this.usedEntry[idx] = true;\n this.indexedPixels[index] = idx;\n idx *= 3;\n var r2 = this.colorTab[idx];\n var g2 = this.colorTab[idx + 1];\n var b2 = this.colorTab[idx + 2];\n\n var er = r1 - r2;\n var eg = g1 - g2;\n var eb = b1 - b2;\n\n for (var i = (direction == 1 ? 0: ds.length - 1), end = (direction == 1 ? ds.length : 0); i !== end; i += direction) {\n var x1 = ds[i][1]; // *direction; // Should this by timesd by direction?..to make the kernel go in the opposite direction....got no idea....\n var y1 = ds[i][2];\n if (x1 + x >= 0 && x1 + x < width && y1 + y >= 0 && y1 + y < height) {\n var d = ds[i][0];\n idx = index + x1 + (y1 * width);\n idx *= 3;\n\n data[idx] = Math.max(0, Math.min(255, data[idx] + er * d));\n data[idx + 1] = Math.max(0, Math.min(255, data[idx + 1] + eg * d));\n data[idx + 2] = Math.max(0, Math.min(255, data[idx + 2] + eb * d));\n }\n }\n }\n }\n};\n\n/*\n Returns index of palette color closest to c\n*/\nGIFEncoder.prototype.findClosest = function(c, used) {\n return this.findClosestRGB((c & 0xFF0000) >> 16, (c & 0x00FF00) >> 8, (c & 0x0000FF), used);\n};\n\nGIFEncoder.prototype.findClosestRGB = function(r, g, b, used) {\n if (this.colorTab === null) return -1;\n\n if (this.neuQuant && !used) {\n return this.neuQuant.lookupRGB(r, g, b);\n }\n \n var c = b | (g << 8) | (r << 16);\n\n var minpos = 0;\n var dmin = 256 * 256 * 256;\n var len = this.colorTab.length;\n\n for (var i = 0, index = 0; i < len; index++) {\n var dr = r - (this.colorTab[i++] & 0xff);\n var dg = g - (this.colorTab[i++] & 0xff);\n var db = b - (this.colorTab[i++] & 0xff);\n var d = dr * dr + dg * dg + db * db;\n if ((!used || this.usedEntry[index]) && (d < dmin)) {\n dmin = d;\n minpos = index;\n }\n }\n\n return minpos;\n};\n\n/*\n Extracts image pixels into byte array pixels\n (removes alphachannel from canvas imagedata)\n*/\nGIFEncoder.prototype.getImagePixels = function() {\n var w = this.width;\n var h = this.height;\n this.pixels = new Uint8Array(w * h * 3);\n\n var data = this.image;\n var srcPos = 0;\n var count = 0;\n\n for (var i = 0; i < h; i++) {\n for (var j = 0; j < w; j++) {\n this.pixels[count++] = data[srcPos++];\n this.pixels[count++] = data[srcPos++];\n this.pixels[count++] = data[srcPos++];\n srcPos++;\n }\n }\n};\n\n/*\n Writes Graphic Control Extension\n*/\nGIFEncoder.prototype.writeGraphicCtrlExt = function() {\n this.out.writeByte(0x21); // extension introducer\n this.out.writeByte(0xf9); // GCE label\n this.out.writeByte(4); // data block size\n\n var transp, disp;\n if (this.transparent === null) {\n transp = 0;\n disp = 0; // dispose = no action\n } else {\n transp = 1;\n disp = 2; // force clear if using transparent color\n }\n\n if (this.dispose >= 0) {\n disp = dispose & 7; // user override\n }\n disp <<= 2;\n\n // packed fields\n this.out.writeByte(\n 0 | // 1:3 reserved\n disp | // 4:6 disposal\n 0 | // 7 user input - 0 = none\n transp // 8 transparency flag\n );\n\n this.writeShort(this.delay); // delay x 1/100 sec\n this.out.writeByte(this.transIndex); // transparent color index\n this.out.writeByte(0); // block terminator\n};\n\n/*\n Writes Image Descriptor\n*/\nGIFEncoder.prototype.writeImageDesc = function() {\n this.out.writeByte(0x2c); // image separator\n this.writeShort(0); // image position x,y = 0,0\n this.writeShort(0);\n this.writeShort(this.width); // image size\n this.writeShort(this.height);\n\n // packed fields\n if (this.firstFrame || this.globalPalette) {\n // no LCT - GCT is used for first (or only) frame\n this.out.writeByte(0);\n } else {\n // specify normal LCT\n this.out.writeByte(\n 0x80 | // 1 local color table 1=yes\n 0 | // 2 interlace - 0=no\n 0 | // 3 sorted - 0=no\n 0 | // 4-5 reserved\n this.palSize // 6-8 size of color table\n );\n }\n};\n\n/*\n Writes Logical Screen Descriptor\n*/\nGIFEncoder.prototype.writeLSD = function() {\n // logical screen size\n this.writeShort(this.width);\n this.writeShort(this.height);\n\n // packed fields\n this.out.writeByte(\n 0x80 | // 1 : global color table flag = 1 (gct used)\n 0x70 | // 2-4 : color resolution = 7\n 0x00 | // 5 : gct sort flag = 0\n this.palSize // 6-8 : gct size\n );\n\n this.out.writeByte(0); // background color index\n this.out.writeByte(0); // pixel aspect ratio - assume 1:1\n};\n\n/*\n Writes Netscape application extension to define repeat count.\n*/\nGIFEncoder.prototype.writeNetscapeExt = function() {\n this.out.writeByte(0x21); // extension introducer\n this.out.writeByte(0xff); // app extension label\n this.out.writeByte(11); // block size\n this.out.writeUTFBytes('NETSCAPE2.0'); // app id + auth code\n this.out.writeByte(3); // sub-block size\n this.out.writeByte(1); // loop sub-block id\n this.writeShort(this.repeat); // loop count (extra iterations, 0=repeat forever)\n this.out.writeByte(0); // block terminator\n};\n\n/*\n Writes color table\n*/\nGIFEncoder.prototype.writePalette = function() {\n this.out.writeBytes(this.colorTab);\n var n = (3 * 256) - this.colorTab.length;\n for (var i = 0; i < n; i++)\n this.out.writeByte(0);\n};\n\nGIFEncoder.prototype.writeShort = function(pValue) {\n this.out.writeByte(pValue & 0xFF);\n this.out.writeByte((pValue >> 8) & 0xFF);\n};\n\n/*\n Encodes and writes pixel data\n*/\nGIFEncoder.prototype.writePixels = function() {\n var enc = new LZWEncoder(this.width, this.height, this.indexedPixels, this.colorDepth);\n enc.encode(this.out);\n};\n\n/*\n Retrieves the GIF stream\n*/\nGIFEncoder.prototype.stream = function() {\n return this.out;\n};\n\nmodule.exports = GIFEncoder;\n","/*\n LZWEncoder.js\n\n Authors\n Kevin Weiner (original Java version - kweiner@fmsware.com)\n Thibault Imbert (AS3 version - bytearray.org)\n Johan Nordberg (JS version - code@johan-nordberg.com)\n\n Acknowledgements\n GIFCOMPR.C - GIF Image compression routines\n Lempel-Ziv compression based on 'compress'. GIF modifications by\n David Rowley (mgardi@watdcsu.waterloo.edu)\n GIF Image compression - modified 'compress'\n Based on: compress.c - File compression ala IEEE Computer, June 1984.\n By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)\n Jim McKie (decvax!mcvax!jim)\n Steve Davies (decvax!vax135!petsd!peora!srd)\n Ken Turkowski (decvax!decwrl!turtlevax!ken)\n James A. Woods (decvax!ihnp4!ames!jaw)\n Joe Orost (decvax!vax135!petsd!joe)\n*/\n\nvar EOF = -1;\nvar BITS = 12;\nvar HSIZE = 5003; // 80% occupancy\nvar masks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,\n 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,\n 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF];\n\nfunction LZWEncoder(width, height, pixels, colorDepth) {\n var initCodeSize = Math.max(2, colorDepth);\n\n var accum = new Uint8Array(256);\n var htab = new Int32Array(HSIZE);\n var codetab = new Int32Array(HSIZE);\n\n var cur_accum, cur_bits = 0;\n var a_count;\n var free_ent = 0; // first unused entry\n var maxcode;\n\n // block compression parameters -- after all codes are used up,\n // and compression rate changes, start over.\n var clear_flg = false;\n\n // Algorithm: use open addressing double hashing (no chaining) on the\n // prefix code / next character combination. We do a variant of Knuth's\n // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime\n // secondary probe. Here, the modular division first probe is gives way\n // to a faster exclusive-or manipulation. Also do block compression with\n // an adaptive reset, whereby the code table is cleared when the compression\n // ratio decreases, but after the table fills. The variable-length output\n // codes are re-sized at this point, and a special CLEAR code is generated\n // for the decompressor. Late addition: construct the table according to\n // file size for noticeable speed improvement on small files. Please direct\n // questions about this implementation to ames!jaw.\n var g_init_bits, ClearCode, EOFCode;\n\n // Add a character to the end of the current packet, and if it is 254\n // characters, flush the packet to disk.\n function char_out(c, outs) {\n accum[a_count++] = c;\n if (a_count >= 254) flush_char(outs);\n }\n\n // Clear out the hash table\n // table clear for block compress\n function cl_block(outs) {\n cl_hash(HSIZE);\n free_ent = ClearCode + 2;\n clear_flg = true;\n output(ClearCode, outs);\n }\n\n // Reset code table\n function cl_hash(hsize) {\n for (var i = 0; i < hsize; ++i) htab[i] = -1;\n }\n\n function compress(init_bits, outs) {\n var fcode, c, i, ent, disp, hsize_reg, hshift;\n\n // Set up the globals: g_init_bits - initial number of bits\n g_init_bits = init_bits;\n\n // Set up the necessary values\n clear_flg = false;\n n_bits = g_init_bits;\n maxcode = MAXCODE(n_bits);\n\n ClearCode = 1 << (init_bits - 1);\n EOFCode = ClearCode + 1;\n free_ent = ClearCode + 2;\n\n a_count = 0; // clear packet\n\n ent = nextPixel();\n\n hshift = 0;\n for (fcode = HSIZE; fcode < 65536; fcode *= 2) ++hshift;\n hshift = 8 - hshift; // set hash code range bound\n hsize_reg = HSIZE;\n cl_hash(hsize_reg); // clear hash table\n\n output(ClearCode, outs);\n\n outer_loop: while ((c = nextPixel()) != EOF) {\n fcode = (c << BITS) + ent;\n i = (c << hshift) ^ ent; // xor hashing\n if (htab[i] === fcode) {\n ent = codetab[i];\n continue;\n } else if (htab[i] >= 0) { // non-empty slot\n disp = hsize_reg - i; // secondary hash (after G. Knott)\n if (i === 0) disp = 1;\n do {\n if ((i -= disp) < 0) i += hsize_reg;\n if (htab[i] === fcode) {\n ent = codetab[i];\n continue outer_loop;\n }\n } while (htab[i] >= 0);\n }\n output(ent, outs);\n ent = c;\n if (free_ent < 1 << BITS) {\n codetab[i] = free_ent++; // code -> hashtable\n htab[i] = fcode;\n } else {\n cl_block(outs);\n }\n }\n\n // Put out the final code.\n output(ent, outs);\n output(EOFCode, outs);\n }\n\n function encode(outs) {\n outs.writeByte(initCodeSize); // write \"initial code size\" byte\n remaining = width * height; // reset navigation variables\n curPixel = 0;\n compress(initCodeSize + 1, outs); // compress and write the pixel data\n outs.writeByte(0); // write block terminator\n }\n\n // Flush the packet to disk, and reset the accumulator\n function flush_char(outs) {\n if (a_count > 0) {\n outs.writeByte(a_count);\n outs.writeBytes(accum, 0, a_count);\n a_count = 0;\n }\n }\n\n function MAXCODE(n_bits) {\n return (1 << n_bits) - 1;\n }\n\n // Return the next pixel from the image\n function nextPixel() {\n if (remaining === 0) return EOF;\n --remaining;\n var pix = pixels[curPixel++];\n return pix & 0xff;\n }\n\n function output(code, outs) {\n cur_accum &= masks[cur_bits];\n\n if (cur_bits > 0) cur_accum |= (code << cur_bits);\n else cur_accum = code;\n\n cur_bits += n_bits;\n\n while (cur_bits >= 8) {\n char_out((cur_accum & 0xff), outs);\n cur_accum >>= 8;\n cur_bits -= 8;\n }\n\n // If the next entry is going to be too big for the code size,\n // then increase it, if possible.\n if (free_ent > maxcode || clear_flg) {\n if (clear_flg) {\n maxcode = MAXCODE(n_bits = g_init_bits);\n clear_flg = false;\n } else {\n ++n_bits;\n if (n_bits == BITS) maxcode = 1 << BITS;\n else maxcode = MAXCODE(n_bits);\n }\n }\n\n if (code == EOFCode) {\n // At EOF, write the rest of the buffer.\n while (cur_bits > 0) {\n char_out((cur_accum & 0xff), outs);\n cur_accum >>= 8;\n cur_bits -= 8;\n }\n flush_char(outs);\n }\n }\n\n this.encode = encode;\n}\n\nmodule.exports = LZWEncoder;\n","/* NeuQuant Neural-Net Quantization Algorithm\n * ------------------------------------------\n *\n * Copyright (c) 1994 Anthony Dekker\n *\n * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.\n * See \"Kohonen neural networks for optimal colour quantization\"\n * in \"Network: Computation in Neural Systems\" Vol. 5 (1994) pp 351-367.\n * for a discussion of the algorithm.\n * See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML\n *\n * Any party obtaining a copy of these files from the author, directly or\n * indirectly, is granted, free of charge, a full and unrestricted irrevocable,\n * world-wide, paid up, royalty-free, nonexclusive right and license to deal\n * in this software and documentation files (the \"Software\"), including without\n * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons who receive\n * copies from any such party to do so, with the only requirement being\n * that this copyright notice remain intact.\n *\n * (JavaScript port 2012 by Johan Nordberg)\n */\n\nvar ncycles = 100; // number of learning cycles\nvar netsize = 256; // number of colors used\nvar maxnetpos = netsize - 1;\n\n// defs for freq and bias\nvar netbiasshift = 4; // bias for colour values\nvar intbiasshift = 16; // bias for fractions\nvar intbias = (1 << intbiasshift);\nvar gammashift = 10;\nvar gamma = (1 << gammashift);\nvar betashift = 10;\nvar beta = (intbias >> betashift); /* beta = 1/1024 */\nvar betagamma = (intbias << (gammashift - betashift));\n\n// defs for decreasing radius factor\nvar initrad = (netsize >> 3); // for 256 cols, radius starts\nvar radiusbiasshift = 6; // at 32.0 biased by 6 bits\nvar radiusbias = (1 << radiusbiasshift);\nvar initradius = (initrad * radiusbias); //and decreases by a\nvar radiusdec = 30; // factor of 1/30 each cycle\n\n// defs for decreasing alpha factor\nvar alphabiasshift = 10; // alpha starts at 1.0\nvar initalpha = (1 << alphabiasshift);\nvar alphadec; // biased by 10 bits\n\n/* radbias and alpharadbias used for radpower calculation */\nvar radbiasshift = 8;\nvar radbias = (1 << radbiasshift);\nvar alpharadbshift = (alphabiasshift + radbiasshift);\nvar alpharadbias = (1 << alpharadbshift);\n\n// four primes near 500 - assume no image has a length so large that it is\n// divisible by all four primes\nvar prime1 = 499;\nvar prime2 = 491;\nvar prime3 = 487;\nvar prime4 = 503;\nvar minpicturebytes = (3 * prime4);\n\n/*\n Constructor: NeuQuant\n\n Arguments:\n\n pixels - array of pixels in RGB format\n samplefac - sampling factor 1 to 30 where lower is better quality\n\n >\n > pixels = [r, g, b, r, g, b, r, g, b, ..]\n >\n*/\nfunction NeuQuant(pixels, samplefac) {\n var network; // int[netsize][4]\n var netindex; // for network lookup - really 256\n\n // bias and freq arrays for learning\n var bias;\n var freq;\n var radpower;\n\n /*\n Private Method: init\n\n sets up arrays\n */\n function init() {\n network = [];\n netindex = new Int32Array(256);\n bias = new Int32Array(netsize);\n freq = new Int32Array(netsize);\n radpower = new Int32Array(netsize >> 3);\n\n var i, v;\n for (i = 0; i < netsize; i++) {\n v = (i << (netbiasshift + 8)) / netsize;\n network[i] = new Float64Array([v, v, v, 0]);\n //network[i] = [v, v, v, 0]\n freq[i] = intbias / netsize;\n bias[i] = 0;\n }\n }\n\n /*\n Private Method: unbiasnet\n\n unbiases network to give byte values 0..255 and record position i to prepare for sort\n */\n function unbiasnet() {\n for (var i = 0; i < netsize; i++) {\n network[i][0] >>= netbiasshift;\n network[i][1] >>= netbiasshift;\n network[i][2] >>= netbiasshift;\n network[i][3] = i; // record color number\n }\n }\n\n /*\n Private Method: altersingle\n\n moves neuron *i* towards biased (b,g,r) by factor *alpha*\n */\n function altersingle(alpha, i, b, g, r) {\n network[i][0] -= (alpha * (network[i][0] - b)) / initalpha;\n network[i][1] -= (alpha * (network[i][1] - g)) / initalpha;\n network[i][2] -= (alpha * (network[i][2] - r)) / initalpha;\n }\n\n /*\n Private Method: alterneigh\n\n moves neurons in *radius* around index *i* towards biased (b,g,r) by factor *alpha*\n */\n function alterneigh(radius, i, b, g, r) {\n var lo = Math.abs(i - radius);\n var hi = Math.min(i + radius, netsize);\n\n var j = i + 1;\n var k = i - 1;\n var m = 1;\n\n var p, a;\n while ((j < hi) || (k > lo)) {\n a = radpower[m++];\n\n if (j < hi) {\n p = network[j++];\n p[0] -= (a * (p[0] - b)) / alpharadbias;\n p[1] -= (a * (p[1] - g)) / alpharadbias;\n p[2] -= (a * (p[2] - r)) / alpharadbias;\n }\n\n if (k > lo) {\n p = network[k--];\n p[0] -= (a * (p[0] - b)) / alpharadbias;\n p[1] -= (a * (p[1] - g)) / alpharadbias;\n p[2] -= (a * (p[2] - r)) / alpharadbias;\n }\n }\n }\n\n /*\n Private Method: contest\n\n searches for biased BGR values\n */\n function contest(b, g, r) {\n /*\n finds closest neuron (min dist) and updates freq\n finds best neuron (min dist-bias) and returns position\n for frequently chosen neurons, freq[i] is high and bias[i] is negative\n bias[i] = gamma * ((1 / netsize) - freq[i])\n */\n\n var bestd = ~(1 << 31);\n var bestbiasd = bestd;\n var bestpos = -1;\n var bestbiaspos = bestpos;\n\n var i, n, dist, biasdist, betafreq;\n for (i = 0; i < netsize; i++) {\n n = network[i];\n\n dist = Math.abs(n[0] - b) + Math.abs(n[1] - g) + Math.abs(n[2] - r);\n if (dist < bestd) {\n bestd = dist;\n bestpos = i;\n }\n\n biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));\n if (biasdist < bestbiasd) {\n bestbiasd = biasdist;\n bestbiaspos = i;\n }\n\n betafreq = (freq[i] >> betashift);\n freq[i] -= betafreq;\n bias[i] += (betafreq << gammashift);\n }\n\n freq[bestpos] += beta;\n bias[bestpos] -= betagamma;\n\n return bestbiaspos;\n }\n\n /*\n Private Method: inxbuild\n\n sorts network and builds netindex[0..255]\n */\n function inxbuild() {\n var i, j, p, q, smallpos, smallval, previouscol = 0, startpos = 0;\n for (i = 0; i < netsize; i++) {\n p = network[i];\n smallpos = i;\n smallval = p[1]; // index on g\n // find smallest in i..netsize-1\n for (j = i + 1; j < netsize; j++) {\n q = network[j];\n if (q[1] < smallval) { // index on g\n smallpos = j;\n smallval = q[1]; // index on g\n }\n }\n q = network[smallpos];\n // swap p (i) and q (smallpos) entries\n if (i != smallpos) {\n j = q[0]; q[0] = p[0]; p[0] = j;\n j = q[1]; q[1] = p[1]; p[1] = j;\n j = q[2]; q[2] = p[2]; p[2] = j;\n j = q[3]; q[3] = p[3]; p[3] = j;\n }\n // smallval entry is now in position i\n\n if (smallval != previouscol) {\n netindex[previouscol] = (startpos + i) >> 1;\n for (j = previouscol + 1; j < smallval; j++)\n netindex[j] = i;\n previouscol = smallval;\n startpos = i;\n }\n }\n netindex[previouscol] = (startpos + maxnetpos) >> 1;\n for (j = previouscol + 1; j < 256; j++)\n netindex[j] = maxnetpos; // really 256\n }\n\n /*\n Private Method: inxsearch\n\n searches for BGR values 0..255 and returns a color index\n */\n function inxsearch(b, g, r) {\n var a, p, dist;\n\n var bestd = 1000; // biggest possible dist is 256*3\n var best = -1;\n\n var i = netindex[g]; // index on g\n var j = i - 1; // start at netindex[g] and work outwards\n\n while ((i < netsize) || (j >= 0)) {\n if (i < netsize) {\n p = network[i];\n dist = p[1] - g; // inx key\n if (dist >= bestd) i = netsize; // stop iter\n else {\n i++;\n if (dist < 0) dist = -dist;\n a = p[0] - b; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n a = p[2] - r; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n bestd = dist;\n best = p[3];\n }\n }\n }\n }\n if (j >= 0) {\n p = network[j];\n dist = g - p[1]; // inx key - reverse dif\n if (dist >= bestd) j = -1; // stop iter\n else {\n j--;\n if (dist < 0) dist = -dist;\n a = p[0] - b; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n a = p[2] - r; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n bestd = dist;\n best = p[3];\n }\n }\n }\n }\n }\n\n return best;\n }\n\n /*\n Private Method: learn\n\n \"Main Learning Loop\"\n */\n function learn() {\n var i;\n\n var lengthcount = pixels.length;\n var alphadec = 30 + ((samplefac - 1) / 3);\n var samplepixels = lengthcount / (3 * samplefac);\n var delta = ~~(samplepixels / ncycles);\n var alpha = initalpha;\n var radius = initradius;\n\n var rad = radius >> radiusbiasshift;\n\n if (rad <= 1) rad = 0;\n for (i = 0; i < rad; i++)\n radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));\n\n var step;\n if (lengthcount < minpicturebytes) {\n samplefac = 1;\n step = 3;\n } else if ((lengthcount % prime1) !== 0) {\n step = 3 * prime1;\n } else if ((lengthcount % prime2) !== 0) {\n step = 3 * prime2;\n } else if ((lengthcount % prime3) !== 0) {\n step = 3 * prime3;\n } else {\n step = 3 * prime4;\n }\n\n var b, g, r, j;\n var pix = 0; // current pixel\n\n i = 0;\n while (i < samplepixels) {\n b = (pixels[pix] & 0xff) << netbiasshift;\n g = (pixels[pix + 1] & 0xff) << netbiasshift;\n r = (pixels[pix + 2] & 0xff) << netbiasshift;\n\n j = contest(b, g, r);\n\n altersingle(alpha, j, b, g, r);\n if (rad !== 0) alterneigh(rad, j, b, g, r); // alter neighbours\n\n pix += step;\n if (pix >= lengthcount) pix -= lengthcount;\n\n i++;\n\n if (delta === 0) delta = 1;\n if (i % delta === 0) {\n alpha -= alpha / alphadec;\n radius -= radius / radiusdec;\n rad = radius >> radiusbiasshift;\n\n if (rad <= 1) rad = 0;\n for (j = 0; j < rad; j++)\n radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));\n }\n }\n }\n\n /*\n Method: buildColormap\n\n 1. initializes network\n 2. trains it\n 3. removes misconceptions\n 4. builds colorindex\n */\n function buildColormap() {\n init();\n learn();\n unbiasnet();\n inxbuild();\n }\n this.buildColormap = buildColormap;\n\n /*\n Method: getColormap\n\n builds colormap from the index\n\n returns array in the format:\n\n >\n > [r, g, b, r, g, b, r, g, b, ..]\n >\n */\n function getColormap() {\n var map = [];\n var index = [];\n\n for (var i = 0; i < netsize; i++)\n index[network[i][3]] = i;\n\n var k = 0;\n for (var l = 0; l < netsize; l++) {\n var j = index[l];\n map[k++] = (network[j][0]);\n map[k++] = (network[j][1]);\n map[k++] = (network[j][2]);\n }\n return map;\n }\n this.getColormap = getColormap;\n\n /*\n Method: lookupRGB\n\n looks for the closest *r*, *g*, *b* color in the map and\n returns its index\n */\n this.lookupRGB = inxsearch;\n}\n\nmodule.exports = NeuQuant;\n","GIFEncoder = require './GIFEncoder.js'\n\nrenderFrame = (frame) ->\n encoder = new GIFEncoder frame.width, frame.height\n\n if frame.index is 0\n encoder.writeHeader()\n else\n encoder.firstFrame = false\n\n encoder.setTransparent frame.transparent\n encoder.setRepeat frame.repeat\n encoder.setDelay frame.delay\n encoder.setQuality frame.quality\n encoder.setDither frame.dither\n encoder.setGlobalPalette frame.globalPalette\n encoder.addFrame frame.data\n encoder.finish() if frame.last\n if frame.globalPalette == true\n frame.globalPalette = encoder.getGlobalPalette()\n\n stream = encoder.stream()\n frame.data = stream.pages\n frame.cursor = stream.cursor\n frame.pageSize = stream.constructor.pageSize\n\n if frame.canTransfer\n transfer = (page.buffer for page in frame.data)\n self.postMessage frame, transfer\n else\n self.postMessage frame\n\nself.onmessage = (event) -> renderFrame event.data\n"]} \ No newline at end of file diff --git a/templates/map/client/libs/jspdf/1.3.2/jspdf.debug.js b/templates/map/client/libs/jspdf/1.3.2/jspdf.debug.js new file mode 100644 index 00000000..c7f0bb8e --- /dev/null +++ b/templates/map/client/libs/jspdf/1.3.2/jspdf.debug.js @@ -0,0 +1,17129 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.jspdf = factory()); +}(this, (function () { 'use strict'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; +}; + + + + + + + + + + + + + + + +var get$1 = function get$1(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get$1(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } +}; + + + + + + + + + + + + + + + + + +var set$1 = function set$1(object, property, value, receiver) { + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent !== null) { + set$1(parent, property, value, receiver); + } + } else if ("value" in desc && desc.writable) { + desc.value = value; + } else { + var setter = desc.set; + + if (setter !== undefined) { + setter.call(receiver, value); + } + } + + return value; +}; + +/** @preserve + * jsPDF - PDF Document creation from JavaScript + * Version 1.3.2 Built on 2016-10-07T02:03:54.044Z + * CommitID b0c67949b0 + * + * Copyright (c) 2010-2016 James Hall , https://github.com/MrRio/jsPDF + * 2010 Aaron Spike, https://github.com/acspike + * 2012 Willow Systems Corporation, willow-systems.com + * 2012 Pablo Hess, https://github.com/pablohess + * 2012 Florian Jenett, https://github.com/fjenett + * 2013 Warren Weckesser, https://github.com/warrenweckesser + * 2013 Youssef Beddad, https://github.com/lifof + * 2013 Lee Driscoll, https://github.com/lsdriscoll + * 2013 Stefan Slonevskiy, https://github.com/stefslon + * 2013 Jeremy Morel, https://github.com/jmorel + * 2013 Christoph Hartmann, https://github.com/chris-rock + * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria + * 2014 James Makes, https://github.com/dollaruw + * 2014 Diego Casorran, https://github.com/diegocr + * 2014 Steven Spungin, https://github.com/Flamenco + * 2014 Kenneth Glassey, https://github.com/Gavvers + * + * Licensed under the MIT License + * + * Contributor(s): + * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, + * kim3er, mfo, alnorth, Flamenco + */ + +/** + * Creates new jsPDF document object instance. + * + * @class + * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l") + * @param unit Measurement unit to be used when coordinates are specified. + * One of "pt" (points), "mm" (Default), "cm", "in" + * @param format One of 'pageFormats' as shown below, default: a4 + * @returns {jsPDF} + * @name jsPDF + */ +var jsPDF = function (global) { + 'use strict'; + + var pdfVersion = '1.3', + pageFormats = { // Size in pt of various paper formats + 'a0': [2383.94, 3370.39], + 'a1': [1683.78, 2383.94], + 'a2': [1190.55, 1683.78], + 'a3': [841.89, 1190.55], + 'a4': [595.28, 841.89], + 'a5': [419.53, 595.28], + 'a6': [297.64, 419.53], + 'a7': [209.76, 297.64], + 'a8': [147.40, 209.76], + 'a9': [104.88, 147.40], + 'a10': [73.70, 104.88], + 'b0': [2834.65, 4008.19], + 'b1': [2004.09, 2834.65], + 'b2': [1417.32, 2004.09], + 'b3': [1000.63, 1417.32], + 'b4': [708.66, 1000.63], + 'b5': [498.90, 708.66], + 'b6': [354.33, 498.90], + 'b7': [249.45, 354.33], + 'b8': [175.75, 249.45], + 'b9': [124.72, 175.75], + 'b10': [87.87, 124.72], + 'c0': [2599.37, 3676.54], + 'c1': [1836.85, 2599.37], + 'c2': [1298.27, 1836.85], + 'c3': [918.43, 1298.27], + 'c4': [649.13, 918.43], + 'c5': [459.21, 649.13], + 'c6': [323.15, 459.21], + 'c7': [229.61, 323.15], + 'c8': [161.57, 229.61], + 'c9': [113.39, 161.57], + 'c10': [79.37, 113.39], + 'dl': [311.81, 623.62], + 'letter': [612, 792], + 'government-letter': [576, 756], + 'legal': [612, 1008], + 'junior-legal': [576, 360], + 'ledger': [1224, 792], + 'tabloid': [792, 1224], + 'credit-card': [153, 243] + }; + + /** + * jsPDF's Internal PubSub Implementation. + * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html + * Backward compatible rewritten on 2014 by + * Diego Casorran, https://github.com/diegocr + * + * @class + * @name PubSub + */ + function PubSub(context) { + var topics = {}; + + this.subscribe = function (topic, callback, once) { + if (typeof callback !== 'function') { + return false; + } + + if (!topics.hasOwnProperty(topic)) { + topics[topic] = {}; + } + + var id = Math.random().toString(35); + topics[topic][id] = [callback, !!once]; + + return id; + }; + + this.unsubscribe = function (token) { + for (var topic in topics) { + if (topics[topic][token]) { + delete topics[topic][token]; + return true; + } + } + return false; + }; + + this.publish = function (topic) { + if (topics.hasOwnProperty(topic)) { + var args = Array.prototype.slice.call(arguments, 1), + idr = []; + + for (var id in topics[topic]) { + var sub = topics[topic][id]; + try { + sub[0].apply(context, args); + } catch (ex) { + if (global.console) { + console.error('jsPDF PubSub Error', ex.message, ex); + } + } + if (sub[1]) idr.push(id); + } + if (idr.length) idr.forEach(this.unsubscribe); + } + }; + } + + /** + * @constructor + * @private + */ + function jsPDF(orientation, unit, format, compressPdf) { + var options = {}; + + if ((typeof orientation === 'undefined' ? 'undefined' : _typeof(orientation)) === 'object') { + options = orientation; + + orientation = options.orientation; + unit = options.unit || unit; + format = options.format || format; + compressPdf = options.compress || options.compressPdf || compressPdf; + } + + // Default options + unit = unit || 'mm'; + format = format || 'a4'; + orientation = ('' + (orientation || 'P')).toLowerCase(); + + var format_as_string = ('' + format).toLowerCase(), + compress = !!compressPdf && typeof Uint8Array === 'function', + textColor = options.textColor || '0 g', + drawColor = options.drawColor || '0 G', + activeFontSize = options.fontSize || 16, + lineHeightProportion = options.lineHeight || 1.15, + lineWidth = options.lineWidth || 0.200025, + // 2mm + objectNumber = 2, + // 'n' Current object number + outToPages = !1, + // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content + offsets = [], + // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes. + fonts = {}, + // collection of font objects, where key is fontKey - a dynamically created label for a given font. + fontmap = {}, + // mapping structure fontName > fontStyle > font key - performance layer. See addFont() + activeFontKey, + // will be string representing the KEY of the font as combination of fontName + fontStyle + k, + // Scale factor + tmp, + page = 0, + currentPage, + pages = [], + pagesContext = [], + // same index as pages and pagedim + pagedim = [], + content = [], + additionalObjects = [], + lineCapID = 0, + lineJoinID = 0, + content_length = 0, + pageWidth, + pageHeight, + pageMode, + zoomMode, + layoutMode, + documentProperties = { + 'title': '', + 'subject': '', + 'author': '', + 'keywords': '', + 'creator': '' + }, + API = {}, + events = new PubSub(API), + + + ///////////////////// + // Private functions + ///////////////////// + f2 = function f2(number) { + return number.toFixed(2); // Ie, %.2f + }, + f3 = function f3(number) { + return number.toFixed(3); // Ie, %.3f + }, + padd2 = function padd2(number) { + return ('0' + parseInt(number)).slice(-2); + }, + out = function out(string) { + if (outToPages) { + /* set by beginPage */ + pages[currentPage].push(string); + } else { + // +1 for '\n' that will be used to join 'content' + content_length += string.length + 1; + content.push(string); + } + }, + newObject = function newObject() { + // Begin a new object + objectNumber++; + offsets[objectNumber] = content_length; + out(objectNumber + ' 0 obj'); + return objectNumber; + }, + + // Does not output the object until after the pages have been output. + // Returns an object containing the objectId and content. + // All pages have been added so the object ID can be estimated to start right after. + // This does not modify the current objectNumber; It must be updated after the newObjects are output. + newAdditionalObject = function newAdditionalObject() { + var objId = pages.length * 2 + 1; + objId += additionalObjects.length; + var obj = { + objId: objId, + content: '' + }; + additionalObjects.push(obj); + return obj; + }, + + // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data + newObjectDeferred = function newObjectDeferred() { + objectNumber++; + offsets[objectNumber] = function () { + return content_length; + }; + return objectNumber; + }, + newObjectDeferredBegin = function newObjectDeferredBegin(oid) { + offsets[oid] = content_length; + }, + putStream = function putStream(str) { + out('stream'); + out(str); + out('endstream'); + }, + putPages = function putPages() { + var n, + p, + arr, + i, + deflater, + adler32, + adler32cs, + wPt, + hPt, + pageObjectNumbers = []; + + adler32cs = global.adler32cs || jsPDF.adler32cs; + if (compress && typeof adler32cs === 'undefined') { + compress = false; + } + + // outToPages = false as set in endDocument(). out() writes to content. + + for (n = 1; n <= page; n++) { + pageObjectNumbers.push(newObject()); + wPt = (pageWidth = pagedim[n].width) * k; + hPt = (pageHeight = pagedim[n].height) * k; + out('<>'); + out('endobj'); + + // Page content + p = pages[n].join('\n'); + newObject(); + if (compress) { + arr = []; + i = p.length; + while (i--) { + arr[i] = p.charCodeAt(i); + } + adler32 = adler32cs.from(p); + deflater = new Deflater(6); + deflater.append(new Uint8Array(arr)); + p = deflater.flush(); + arr = new Uint8Array(p.length + 6); + arr.set(new Uint8Array([120, 156])), arr.set(p, 2); + arr.set(new Uint8Array([adler32 & 0xFF, adler32 >> 8 & 0xFF, adler32 >> 16 & 0xFF, adler32 >> 24 & 0xFF]), p.length + 2); + p = String.fromCharCode.apply(null, arr); + out('<>'); + } else { + out('<>'); + } + putStream(p); + out('endobj'); + } + offsets[1] = content_length; + out('1 0 obj'); + out('<>'); + out('endobj'); + events.publish('postPutPages'); + }, + putFont = function putFont(font) { + font.objectNumber = newObject(); + out('<>'); + out('endobj'); + }, + putFonts = function putFonts() { + for (var fontKey in fonts) { + if (fonts.hasOwnProperty(fontKey)) { + putFont(fonts[fontKey]); + } + } + }, + putXobjectDict = function putXobjectDict() { + // Loop through images, or other data objects + events.publish('putXobjectDict'); + }, + putResourceDictionary = function putResourceDictionary() { + out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); + out('/Font <<'); + + // Do this for each font, the '1' bit is the index of the font + for (var fontKey in fonts) { + if (fonts.hasOwnProperty(fontKey)) { + out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R'); + } + } + out('>>'); + out('/XObject <<'); + putXobjectDict(); + out('>>'); + }, + putResources = function putResources() { + putFonts(); + events.publish('putResources'); + // Resource dictionary + offsets[2] = content_length; + out('2 0 obj'); + out('<<'); + putResourceDictionary(); + out('>>'); + out('endobj'); + events.publish('postPutResources'); + }, + putAdditionalObjects = function putAdditionalObjects() { + events.publish('putAdditionalObjects'); + for (var i = 0; i < additionalObjects.length; i++) { + var obj = additionalObjects[i]; + offsets[obj.objId] = content_length; + out(obj.objId + ' 0 obj'); + out(obj.content); + out('endobj'); + } + objectNumber += additionalObjects.length; + events.publish('postPutAdditionalObjects'); + }, + addToFontDictionary = function addToFontDictionary(fontKey, fontName, fontStyle) { + // this is mapping structure for quick font key lookup. + // returns the KEY of the font (ex: "F1") for a given + // pair of font name and type (ex: "Arial". "Italic") + if (!fontmap.hasOwnProperty(fontName)) { + fontmap[fontName] = {}; + } + fontmap[fontName][fontStyle] = fontKey; + }, + + /** + * FontObject describes a particular font as member of an instnace of jsPDF + * + * It's a collection of properties like 'id' (to be used in PDF stream), + * 'fontName' (font's family name), 'fontStyle' (font's style variant label) + * + * @class + * @public + * @property id {String} PDF-document-instance-specific label assinged to the font. + * @property PostScriptName {String} PDF specification full name for the font + * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping. + * @name FontObject + */ + addFont = function addFont(PostScriptName, fontName, fontStyle, encoding) { + var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10), + + // This is FontObject + font = fonts[fontKey] = { + 'id': fontKey, + 'PostScriptName': PostScriptName, + 'fontName': fontName, + 'fontStyle': fontStyle, + 'encoding': encoding, + 'metadata': {} + }; + addToFontDictionary(fontKey, fontName, fontStyle); + events.publish('addFont', font); + + return fontKey; + }, + addFonts = function addFonts() { + + var HELVETICA = "helvetica", + TIMES = "times", + COURIER = "courier", + NORMAL = "normal", + BOLD = "bold", + ITALIC = "italic", + BOLD_ITALIC = "bolditalic", + encoding = 'StandardEncoding', + ZAPF = "zapfdingbats", + standardFonts = [['Helvetica', HELVETICA, NORMAL], ['Helvetica-Bold', HELVETICA, BOLD], ['Helvetica-Oblique', HELVETICA, ITALIC], ['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC], ['Courier', COURIER, NORMAL], ['Courier-Bold', COURIER, BOLD], ['Courier-Oblique', COURIER, ITALIC], ['Courier-BoldOblique', COURIER, BOLD_ITALIC], ['Times-Roman', TIMES, NORMAL], ['Times-Bold', TIMES, BOLD], ['Times-Italic', TIMES, ITALIC], ['Times-BoldItalic', TIMES, BOLD_ITALIC], ['ZapfDingbats', ZAPF]]; + + for (var i = 0, l = standardFonts.length; i < l; i++) { + var fontKey = addFont(standardFonts[i][0], standardFonts[i][1], standardFonts[i][2], encoding); + + // adding aliases for standard fonts, this time matching the capitalization + var parts = standardFonts[i][0].split('-'); + addToFontDictionary(fontKey, parts[0], parts[1] || ''); + } + events.publish('addFonts', { + fonts: fonts, + dictionary: fontmap + }); + }, + SAFE = function __safeCall(fn) { + fn.foo = function __safeCallWrapper() { + try { + return fn.apply(this, arguments); + } catch (e) { + var stack = e.stack || ''; + if (~stack.indexOf(' at ')) stack = stack.split(" at ")[1]; + var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message; + if (global.console) { + global.console.error(m, e); + if (global.alert) alert(m); + } else { + throw new Error(m); + } + } + }; + fn.foo.bar = fn; + return fn.foo; + }, + to8bitStream = function to8bitStream(text, flags) { + /** + * PDF 1.3 spec: + * "For text strings encoded in Unicode, the first two bytes must be 254 followed by + * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts + * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely + * to be a meaningful beginning of a word or phrase.) The remainder of the + * string consists of Unicode character codes, according to the UTF-16 encoding + * specified in the Unicode standard, version 2.0. Commonly used Unicode values + * are represented as 2 bytes per character, with the high-order byte appearing first + * in the string." + * + * In other words, if there are chars in a string with char code above 255, we + * recode the string to UCS2 BE - string doubles in length and BOM is prepended. + * + * HOWEVER! + * Actual *content* (body) text (as opposed to strings used in document properties etc) + * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID) + * + * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have + * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could + * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode + * code page. There, however, all characters in the stream are treated as GIDs, + * including BOM, which is the reason we need to skip BOM in content text (i.e. that + * that is tied to a font). + * + * To signal this "special" PDFEscape / to8bitStream handling mode, + * API.text() function sets (unless you overwrite it with manual values + * given to API.text(.., flags) ) + * flags.autoencode = true + * flags.noBOM = true + * + * =================================================================================== + * `flags` properties relied upon: + * .sourceEncoding = string with encoding label. + * "Unicode" by default. = encoding of the incoming text. + * pass some non-existing encoding name + * (ex: 'Do not touch my strings! I know what I am doing.') + * to make encoding code skip the encoding step. + * .outputEncoding = Either valid PDF encoding name + * (must be supported by jsPDF font metrics, otherwise no encoding) + * or a JS object, where key = sourceCharCode, value = outputCharCode + * missing keys will be treated as: sourceCharCode === outputCharCode + * .noBOM + * See comment higher above for explanation for why this is important + * .autoencode + * See comment higher above for explanation for why this is important + */ + + var i, l, sourceEncoding, encodingBlock, outputEncoding, newtext, isUnicode, ch, bch; + + flags = flags || {}; + sourceEncoding = flags.sourceEncoding || 'Unicode'; + outputEncoding = flags.outputEncoding; + + // This 'encoding' section relies on font metrics format + // attached to font objects by, among others, + // "Willow Systems' standard_font_metrics plugin" + // see jspdf.plugin.standard_font_metrics.js for format + // of the font.metadata.encoding Object. + // It should be something like + // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}} + // .widths = {0:width, code:width, ..., 'fof':divisor} + // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...} + if ((flags.autoencode || outputEncoding) && fonts[activeFontKey].metadata && fonts[activeFontKey].metadata[sourceEncoding] && fonts[activeFontKey].metadata[sourceEncoding].encoding) { + encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding; + + // each font has default encoding. Some have it clearly defined. + if (!outputEncoding && fonts[activeFontKey].encoding) { + outputEncoding = fonts[activeFontKey].encoding; + } + + // Hmmm, the above did not work? Let's try again, in different place. + if (!outputEncoding && encodingBlock.codePages) { + outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default + } + + if (typeof outputEncoding === 'string') { + outputEncoding = encodingBlock[outputEncoding]; + } + // we want output encoding to be a JS Object, where + // key = sourceEncoding's character code and + // value = outputEncoding's character code. + if (outputEncoding) { + isUnicode = false; + newtext = []; + for (i = 0, l = text.length; i < l; i++) { + ch = outputEncoding[text.charCodeAt(i)]; + if (ch) { + newtext.push(String.fromCharCode(ch)); + } else { + newtext.push(text[i]); + } + + // since we are looping over chars anyway, might as well + // check for residual unicodeness + if (newtext[i].charCodeAt(0) >> 8) { + /* more than 255 */ + isUnicode = true; + } + } + text = newtext.join(''); + } + } + + i = text.length; + // isUnicode may be set to false above. Hence the triple-equal to undefined + while (isUnicode === undefined && i !== 0) { + if (text.charCodeAt(i - 1) >> 8) { + /* more than 255 */ + isUnicode = true; + } + i--; + } + if (!isUnicode) { + return text; + } + + newtext = flags.noBOM ? [] : [254, 255]; + for (i = 0, l = text.length; i < l; i++) { + ch = text.charCodeAt(i); + bch = ch >> 8; // divide by 256 + if (bch >> 8) { + /* something left after dividing by 256 second time */ + throw new Error("Character at position " + i + " of string '" + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE"); + } + newtext.push(bch); + newtext.push(ch - (bch << 8)); + } + return String.fromCharCode.apply(undefined, newtext); + }, + pdfEscape = function pdfEscape(text, flags) { + /** + * Replace '/', '(', and ')' with pdf-safe versions + * + * Doing to8bitStream does NOT make this PDF display unicode text. For that + * we also need to reference a unicode font and embed it - royal pain in the rear. + * + * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars, + * which JavaScript Strings are happy to provide. So, while we still cannot display + * 2-byte characters property, at least CONDITIONALLY converting (entire string containing) + * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF + * is still parseable. + * This will allow immediate support for unicode in document properties strings. + */ + return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); + }, + putInfo = function putInfo() { + out('/Producer (jsPDF ' + jsPDF.version + ')'); + for (var key in documentProperties) { + if (documentProperties.hasOwnProperty(key) && documentProperties[key]) { + out('/' + key.substr(0, 1).toUpperCase() + key.substr(1) + ' (' + pdfEscape(documentProperties[key]) + ')'); + } + } + var created = new Date(), + tzoffset = created.getTimezoneOffset(), + tzsign = tzoffset < 0 ? '+' : '-', + tzhour = Math.floor(Math.abs(tzoffset / 60)), + tzmin = Math.abs(tzoffset % 60), + tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join(''); + out(['/CreationDate (D:', created.getFullYear(), padd2(created.getMonth() + 1), padd2(created.getDate()), padd2(created.getHours()), padd2(created.getMinutes()), padd2(created.getSeconds()), tzstr, ')'].join('')); + }, + putCatalog = function putCatalog() { + out('/Type /Catalog'); + out('/Pages 1 0 R'); + // PDF13ref Section 7.2.1 + if (!zoomMode) zoomMode = 'fullwidth'; + switch (zoomMode) { + case 'fullwidth': + out('/OpenAction [3 0 R /FitH null]'); + break; + case 'fullheight': + out('/OpenAction [3 0 R /FitV null]'); + break; + case 'fullpage': + out('/OpenAction [3 0 R /Fit]'); + break; + case 'original': + out('/OpenAction [3 0 R /XYZ null null 1]'); + break; + default: + var pcn = '' + zoomMode; + if (pcn.substr(pcn.length - 1) === '%') zoomMode = parseInt(zoomMode) / 100; + if (typeof zoomMode === 'number') { + out('/OpenAction [3 0 R /XYZ null null ' + f2(zoomMode) + ']'); + } + } + if (!layoutMode) layoutMode = 'continuous'; + switch (layoutMode) { + case 'continuous': + out('/PageLayout /OneColumn'); + break; + case 'single': + out('/PageLayout /SinglePage'); + break; + case 'two': + case 'twoleft': + out('/PageLayout /TwoColumnLeft'); + break; + case 'tworight': + out('/PageLayout /TwoColumnRight'); + break; + } + if (pageMode) { + /** + * A name object specifying how the document should be displayed when opened: + * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT + * UseOutlines : Document outline visible + * UseThumbs : Thumbnail images visible + * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible + */ + out('/PageMode /' + pageMode); + } + events.publish('putCatalog'); + }, + putTrailer = function putTrailer() { + out('/Size ' + (objectNumber + 1)); + out('/Root ' + objectNumber + ' 0 R'); + out('/Info ' + (objectNumber - 1) + ' 0 R'); + }, + beginPage = function beginPage(width, height) { + // Dimensions are stored as user units and converted to points on output + var orientation = typeof height === 'string' && height.toLowerCase(); + if (typeof width === 'string') { + var format = width.toLowerCase(); + if (pageFormats.hasOwnProperty(format)) { + width = pageFormats[format][0] / k; + height = pageFormats[format][1] / k; + } + } + if (Array.isArray(width)) { + height = width[1]; + width = width[0]; + } + if (orientation) { + switch (orientation.substr(0, 1)) { + case 'l': + if (height > width) orientation = 's'; + break; + case 'p': + if (width > height) orientation = 's'; + break; + } + if (orientation === 's') { + tmp = width; + width = height; + height = tmp; + } + } + outToPages = true; + pages[++page] = []; + pagedim[page] = { + width: Number(width) || pageWidth, + height: Number(height) || pageHeight + }; + pagesContext[page] = {}; + _setPage(page); + }, + _addPage = function _addPage() { + beginPage.apply(this, arguments); + // Set line width + out(f2(lineWidth * k) + ' w'); + // Set draw color + out(drawColor); + // resurrecting non-default line caps, joins + if (lineCapID !== 0) { + out(lineCapID + ' J'); + } + if (lineJoinID !== 0) { + out(lineJoinID + ' j'); + } + events.publish('addPage', { + pageNumber: page + }); + }, + _deletePage = function _deletePage(n) { + if (n > 0 && n <= page) { + pages.splice(n, 1); + pagedim.splice(n, 1); + page--; + if (currentPage > page) { + currentPage = page; + } + this.setPage(currentPage); + } + }, + _setPage = function _setPage(n) { + if (n > 0 && n <= page) { + currentPage = n; + pageWidth = pagedim[n].width; + pageHeight = pagedim[n].height; + } + }, + + /** + * Returns a document-specific font key - a label assigned to a + * font name + font type combination at the time the font was added + * to the font inventory. + * + * Font key is used as label for the desired font for a block of text + * to be added to the PDF document stream. + * @private + * @function + * @param fontName {String} can be undefined on "falthy" to indicate "use current" + * @param fontStyle {String} can be undefined on "falthy" to indicate "use current" + * @returns {String} Font key. + */ + _getFont = function _getFont(fontName, fontStyle) { + var key; + + fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName; + fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle; + + if (fontName !== undefined) { + fontName = fontName.toLowerCase(); + } + switch (fontName) { + case 'sans-serif': + case 'verdana': + case 'arial': + case 'helvetica': + fontName = 'helvetica'; + break; + case 'fixed': + case 'monospace': + case 'terminal': + case 'courier': + fontName = 'courier'; + break; + case 'serif': + case 'cursive': + case 'fantasy': + default: + fontName = 'times'; + break; + } + + try { + // get a string like 'F3' - the KEY corresponding tot he font + type combination. + key = fontmap[fontName][fontStyle]; + } catch (e) {} + + if (!key) { + //throw new Error("Unable to look up font label for font '" + fontName + "', '" + //+ fontStyle + "'. Refer to getFontList() for available fonts."); + key = fontmap['times'][fontStyle]; + if (key == null) { + key = fontmap['times']['normal']; + } + } + return key; + }, + buildDocument = function buildDocument() { + outToPages = false; // switches out() to content + + objectNumber = 2; + content_length = 0; + content = []; + offsets = []; + additionalObjects = []; + // Added for AcroForm + events.publish('buildDocument'); + + // putHeader() + out('%PDF-' + pdfVersion); + + putPages(); + + // Must happen after putPages + // Modifies current object Id + putAdditionalObjects(); + + putResources(); + + // Info + newObject(); + out('<<'); + putInfo(); + out('>>'); + out('endobj'); + + // Catalog + newObject(); + out('<<'); + putCatalog(); + out('>>'); + out('endobj'); + + // Cross-ref + var o = content_length, + i, + p = "0000000000"; + out('xref'); + out('0 ' + (objectNumber + 1)); + out(p + ' 65535 f '); + for (i = 1; i <= objectNumber; i++) { + var offset = offsets[i]; + if (typeof offset === 'function') { + out((p + offsets[i]()).slice(-10) + ' 00000 n '); + } else { + out((p + offsets[i]).slice(-10) + ' 00000 n '); + } + } + // Trailer + out('trailer'); + out('<<'); + putTrailer(); + out('>>'); + out('startxref'); + out('' + o); + out('%%EOF'); + + outToPages = true; + + return content.join('\n'); + }, + getStyle = function getStyle(style) { + // see path-painting operators in PDF spec + var op = 'S'; // stroke + if (style === 'F') { + op = 'f'; // fill + } else if (style === 'FD' || style === 'DF') { + op = 'B'; // both + } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') { + /* + Allow direct use of these PDF path-painting operators: + - f fill using nonzero winding number rule + - f* fill using even-odd rule + - B fill then stroke with fill using non-zero winding number rule + - B* fill then stroke with fill using even-odd rule + */ + op = style; + } + return op; + }, + getArrayBuffer = function getArrayBuffer() { + var data = buildDocument(), + len = data.length, + ab = new ArrayBuffer(len), + u8 = new Uint8Array(ab); + + while (len--) { + u8[len] = data.charCodeAt(len); + }return ab; + }, + getBlob = function getBlob() { + return new Blob([getArrayBuffer()], { + type: "application/pdf" + }); + }, + + /** + * Generates the PDF document. + * + * If `type` argument is undefined, output is raw body of resulting PDF returned as a string. + * + * @param {String} type A string identifying one of the possible output types. + * @param {Object} options An object providing some additional signalling to PDF generator. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name output + */ + _output = SAFE(function (type, options) { + var datauri = ('' + type).substr(0, 6) === 'dataur' ? 'data:application/pdf;base64,' + btoa(buildDocument()) : 0; + + switch (type) { + case undefined: + return buildDocument(); + case 'save': + if (navigator.getUserMedia) { + if (global.URL === undefined || global.URL.createObjectURL === undefined) { + return API.output('dataurlnewwindow'); + } + } + saveAs(getBlob(), options); + if (typeof saveAs.unload === 'function') { + if (global.setTimeout) { + setTimeout(saveAs.unload, 911); + } + } + break; + case 'arraybuffer': + return getArrayBuffer(); + case 'blob': + return getBlob(); + case 'bloburi': + case 'bloburl': + // User is responsible of calling revokeObjectURL + return global.URL && global.URL.createObjectURL(getBlob()) || void 0; + case 'datauristring': + case 'dataurlstring': + return datauri; + case 'dataurlnewwindow': + var nW = global.open(datauri); + if (nW || typeof safari === "undefined") return nW; + /* pass through */ + case 'datauri': + case 'dataurl': + return global.document.location.href = datauri; + default: + throw new Error('Output type "' + type + '" is not supported.'); + } + // @TODO: Add different output options + }); + + switch (unit) { + case 'pt': + k = 1; + break; + case 'mm': + k = 72 / 25.4000508; + break; + case 'cm': + k = 72 / 2.54000508; + break; + case 'in': + k = 72; + break; + case 'px': + k = 96 / 72; + break; + case 'pc': + k = 12; + break; + case 'em': + k = 12; + break; + case 'ex': + k = 6; + break; + default: + throw 'Invalid unit: ' + unit; + } + + //--------------------------------------- + // Public API + + /** + * Object exposing internal API to plugins + * @public + */ + API.internal = { + 'pdfEscape': pdfEscape, + 'getStyle': getStyle, + /** + * Returns {FontObject} describing a particular font. + * @public + * @function + * @param fontName {String} (Optional) Font's family name + * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic") + * @returns {FontObject} + */ + 'getFont': function getFont() { + return fonts[_getFont.apply(API, arguments)]; + }, + 'getFontSize': function getFontSize() { + return activeFontSize; + }, + 'getLineHeight': function getLineHeight() { + return activeFontSize * lineHeightProportion; + }, + 'write': function write(string1 /*, string2, string3, etc */) { + out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' ')); + }, + 'getCoordinateString': function getCoordinateString(value) { + return f2(value * k); + }, + 'getVerticalCoordinateString': function getVerticalCoordinateString(value) { + return f2((pageHeight - value) * k); + }, + 'collections': {}, + 'newObject': newObject, + 'newAdditionalObject': newAdditionalObject, + 'newObjectDeferred': newObjectDeferred, + 'newObjectDeferredBegin': newObjectDeferredBegin, + 'putStream': putStream, + 'events': events, + // ratio that you use in multiplication of a given "size" number to arrive to 'point' + // units of measurement. + // scaleFactor is set at initialization of the document and calculated against the stated + // default measurement units for the document. + // If default is "mm", k is the number that will turn number in 'mm' into 'points' number. + // through multiplication. + 'scaleFactor': k, + 'pageSize': { + get width() { + return pageWidth; + }, + get height() { + return pageHeight; + } + }, + 'output': function output(type, options) { + return _output(type, options); + }, + 'getNumberOfPages': function getNumberOfPages() { + return pages.length - 1; + }, + 'pages': pages, + 'out': out, + 'f2': f2, + 'getPageInfo': function getPageInfo(pageNumberOneBased) { + var objId = (pageNumberOneBased - 1) * 2 + 3; + return { + objId: objId, + pageNumber: pageNumberOneBased, + pageContext: pagesContext[pageNumberOneBased] + }; + }, + 'getCurrentPageInfo': function getCurrentPageInfo() { + var objId = (currentPage - 1) * 2 + 3; + return { + objId: objId, + pageNumber: currentPage, + pageContext: pagesContext[currentPage] + }; + }, + 'getPDFVersion': function getPDFVersion() { + return pdfVersion; + } + }; + + /** + * Adds (and transfers the focus to) new page to the PDF document. + * @function + * @returns {jsPDF} + * + * @methodOf jsPDF# + * @name addPage + */ + API.addPage = function () { + _addPage.apply(this, arguments); + return this; + }; + /** + * Adds (and transfers the focus to) new page to the PDF document. + * @function + * @returns {jsPDF} + * + * @methodOf jsPDF# + * @name setPage + * @param {Number} page Switch the active page to the page number specified + * @example + * doc = jsPDF() + * doc.addPage() + * doc.addPage() + * doc.text('I am on page 3') + * doc.setPage(1) + * doc.text('I am on page 1') + */ + API.setPage = function () { + _setPage.apply(this, arguments); + return this; + }; + API.insertPage = function (beforePage) { + this.addPage(); + this.movePage(currentPage, beforePage); + return this; + }; + API.movePage = function (targetPage, beforePage) { + if (targetPage > beforePage) { + var tmpPages = pages[targetPage]; + var tmpPagedim = pagedim[targetPage]; + var tmpPagesContext = pagesContext[targetPage]; + for (var i = targetPage; i > beforePage; i--) { + pages[i] = pages[i - 1]; + pagedim[i] = pagedim[i - 1]; + pagesContext[i] = pagesContext[i - 1]; + } + pages[beforePage] = tmpPages; + pagedim[beforePage] = tmpPagedim; + pagesContext[beforePage] = tmpPagesContext; + this.setPage(beforePage); + } else if (targetPage < beforePage) { + var tmpPages = pages[targetPage]; + var tmpPagedim = pagedim[targetPage]; + var tmpPagesContext = pagesContext[targetPage]; + for (var i = targetPage; i < beforePage; i++) { + pages[i] = pages[i + 1]; + pagedim[i] = pagedim[i + 1]; + pagesContext[i] = pagesContext[i + 1]; + } + pages[beforePage] = tmpPages; + pagedim[beforePage] = tmpPagedim; + pagesContext[beforePage] = tmpPagesContext; + this.setPage(beforePage); + } + return this; + }; + + API.deletePage = function () { + _deletePage.apply(this, arguments); + return this; + }; + API.setDisplayMode = function (zoom, layout, pmode) { + zoomMode = zoom; + layoutMode = layout; + pageMode = pmode; + return this; + }, + + /** + * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings. + * + * @function + * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call. + * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Object} flags Collection of settings signalling how the text must be encoded. Defaults are sane. If you think you want to pass some flags, you likely can read the source. + * @returns {jsPDF} + * @methodOf jsPDF# + * @name text + */ + API.text = function (text, x, y, flags, angle, align) { + /** + * Inserts something like this into PDF + * BT + * /F1 16 Tf % Font name + size + * 16 TL % How many units down for next line in multiline text + * 0 g % color + * 28.35 813.54 Td % position + * (line one) Tj + * T* (line two) Tj + * T* (line three) Tj + * ET + */ + function ESC(s) { + s = s.split("\t").join(Array(options.TabLen || 9).join(" ")); + return pdfEscape(s, flags); + } + + // Pre-August-2012 the order of arguments was function(x, y, text, flags) + // in effort to make all calls have similar signature like + // function(data, coordinates... , miscellaneous) + // this method had its args flipped. + // code below allows backward compatibility with old arg order. + if (typeof text === 'number') { + tmp = y; + y = x; + x = text; + text = tmp; + } + + // If there are any newlines in text, we assume + // the user wanted to print multiple lines, so break the + // text up into an array. If the text is already an array, + // we assume the user knows what they are doing. + // Convert text into an array anyway to simplify + // later code. + if (typeof text === 'string') { + if (text.match(/[\n\r]/)) { + text = text.split(/\r\n|\r|\n/g); + } else { + text = [text]; + } + } + if (typeof angle === 'string') { + align = angle; + angle = null; + } + if (typeof flags === 'string') { + align = flags; + flags = null; + } + if (typeof flags === 'number') { + angle = flags; + flags = null; + } + var xtra = '', + mode = 'Td', + todo; + if (angle) { + angle *= Math.PI / 180; + var c = Math.cos(angle), + s = Math.sin(angle); + xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" "); + mode = 'Tm'; + } + flags = flags || {}; + if (!('noBOM' in flags)) flags.noBOM = true; + if (!('autoencode' in flags)) flags.autoencode = true; + + var strokeOption = ''; + var pageContext = this.internal.getCurrentPageInfo().pageContext; + if (true === flags.stroke) { + if (pageContext.lastTextWasStroke !== true) { + strokeOption = '1 Tr\n'; + pageContext.lastTextWasStroke = true; + } + } else { + if (pageContext.lastTextWasStroke) { + strokeOption = '0 Tr\n'; + } + pageContext.lastTextWasStroke = false; + } + + if (typeof this._runningPageHeight === 'undefined') { + this._runningPageHeight = 0; + } + + if (typeof text === 'string') { + text = ESC(text); + } else if (Object.prototype.toString.call(text) === '[object Array]') { + // we don't want to destroy original text array, so cloning it + var sa = text.concat(), + da = [], + len = sa.length; + // we do array.join('text that must not be PDFescaped") + // thus, pdfEscape each component separately + while (len--) { + da.push(ESC(sa.shift())); + } + var linesLeft = Math.ceil((pageHeight - y - this._runningPageHeight) * k / (activeFontSize * lineHeightProportion)); + if (0 <= linesLeft && linesLeft < da.length + 1) { + //todo = da.splice(linesLeft-1); + } + + if (align) { + var left, + prevX, + maxLineLength, + leading = activeFontSize * lineHeightProportion, + lineWidths = text.map(function (v) { + return this.getStringUnitWidth(v) * activeFontSize / k; + }, this); + maxLineLength = Math.max.apply(Math, lineWidths); + // The first line uses the "main" Td setting, + // and the subsequent lines are offset by the + // previous line's x coordinate. + if (align === "center") { + // The passed in x coordinate defines + // the center point. + left = x - maxLineLength / 2; + x -= lineWidths[0] / 2; + } else if (align === "right") { + // The passed in x coordinate defines the + // rightmost point of the text. + left = x - maxLineLength; + x -= lineWidths[0]; + } else { + throw new Error('Unrecognized alignment option, use "center" or "right".'); + } + prevX = x; + text = da[0]; + for (var i = 1, len = da.length; i < len; i++) { + var delta = maxLineLength - lineWidths[i]; + if (align === "center") delta /= 2; + // T* = x-offset leading Td ( text ) + text += ") Tj\n" + (left - prevX + delta) + " -" + leading + " Td (" + da[i]; + prevX = left + delta; + } + } else { + text = da.join(") Tj\nT* ("); + } + } else { + throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.'); + } + // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates + + // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET + // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations) + // Thus, there is NO useful, *reliable* concept of "default" font for a page. + // The fact that "default" (reuse font used before) font worked before in basic cases is an accident + // - readers dealing smartly with brokenness of jsPDF's markup. + + var curY; + + if (todo) { + //this.addPage(); + //this._runningPageHeight += y - (activeFontSize * 1.7 / k); + //curY = f2(pageHeight - activeFontSize * 1.7 /k); + } else { + curY = f2((pageHeight - y) * k); + } + //curY = f2((pageHeight - (y - this._runningPageHeight)) * k); + + // if (curY < 0){ + // console.log('auto page break'); + // this.addPage(); + // this._runningPageHeight = y - (activeFontSize * 1.7 / k); + // curY = f2(pageHeight - activeFontSize * 1.7 /k); + // } + + out('BT\n/' + activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size + activeFontSize * lineHeightProportion + ' TL\n' + // line spacing + strokeOption + // stroke option + textColor + '\n' + xtra + f2(x * k) + ' ' + curY + ' ' + mode + '\n(' + text + ') Tj\nET'); + + if (todo) { + //this.text( todo, x, activeFontSize * 1.7 / k); + //this.text( todo, x, this._runningPageHeight + (activeFontSize * 1.7 / k)); + this.text(todo, x, y); // + (activeFontSize * 1.7 / k)); + } + + return this; + }; + + API.lstext = function (text, x, y, spacing) { + for (var i = 0, len = text.length; i < len; i++, x += spacing) { + this.text(text[i], x, y); + } + }; + + API.line = function (x1, y1, x2, y2) { + return this.lines([[x2 - x1, y2 - y1]], x1, y1); + }; + + API.clip = function () { + // By patrick-roberts, github.com/MrRio/jsPDF/issues/328 + // Call .clip() after calling .rect() with a style argument of null + out('W'); // clip + out('S'); // stroke path; necessary for clip to work + }; + + /** + * This fixes the previous function clip(). Perhaps the 'stroke path' hack was due to the missing 'n' instruction? + * We introduce the fixed version so as to not break API. + * @param fillRule + */ + API.clip_fixed = function (fillRule) { + // Call .clip() after calling drawing ops with a style argument of null + // W is the PDF clipping op + if ('evenodd' === fillRule) { + out('W*'); + } else { + out('W'); + } + // End the path object without filling or stroking it. + // This operator is a path-painting no-op, used primarily for the side effect of changing the current clipping path + // (see Section 4.4.3, “Clipping Path Operators”) + out('n'); + }; + + /** + * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates. + * All data points in `lines` are relative to last line origin. + * `x`, `y` become x1,y1 for first line / curve in the set. + * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point. + * For bezier curves you need to specify [x2,y2,x3,y3,x4,y4] - vectors to control points 1, 2, ending point. All vectors are against the start of the curve - x1,y1. + * + * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line + * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves). + * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} scale (Defaults to [1.0,1.0]) x,y Scaling factor for all vectors. Elements can be any floating number Sub-one makes drawing smaller. Over-one grows the drawing. Negative flips the direction. + * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. + * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name lines + */ + API.lines = function (lines, x, y, scale, style, closed) { + var scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4; + + // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style) + // in effort to make all calls have similar signature like + // function(content, coordinateX, coordinateY , miscellaneous) + // this method had its args flipped. + // code below allows backward compatibility with old arg order. + if (typeof lines === 'number') { + tmp = y; + y = x; + x = lines; + lines = tmp; + } + + scale = scale || [1, 1]; + + // starting point + out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m '); + + scalex = scale[0]; + scaley = scale[1]; + l = lines.length; + //, x2, y2 // bezier only. In page default measurement "units", *after* scaling + //, x3, y3 // bezier only. In page default measurement "units", *after* scaling + // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling + x4 = x; // last / ending point = starting point for first item. + y4 = y; // last / ending point = starting point for first item. + + for (i = 0; i < l; i++) { + leg = lines[i]; + if (leg.length === 2) { + // simple line + x4 = leg[0] * scalex + x4; // here last x4 was prior ending point + y4 = leg[1] * scaley + y4; // here last y4 was prior ending point + out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l'); + } else { + // bezier curve + x2 = leg[0] * scalex + x4; // here last x4 is prior ending point + y2 = leg[1] * scaley + y4; // here last y4 is prior ending point + x3 = leg[2] * scalex + x4; // here last x4 is prior ending point + y3 = leg[3] * scaley + y4; // here last y4 is prior ending point + x4 = leg[4] * scalex + x4; // here last x4 was prior ending point + y4 = leg[5] * scaley + y4; // here last y4 was prior ending point + out(f3(x2 * k) + ' ' + f3((pageHeight - y2) * k) + ' ' + f3(x3 * k) + ' ' + f3((pageHeight - y3) * k) + ' ' + f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' c'); + } + } + + if (closed) { + out(' h'); + } + + // stroking / filling / both the path + if (style !== null) { + out(getStyle(style)); + } + return this; + }; + + /** + * Adds a rectangle to PDF + * + * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} w Width (in units declared at inception of PDF document) + * @param {Number} h Height (in units declared at inception of PDF document) + * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name rect + */ + API.rect = function (x, y, w, h, style) { + var op = getStyle(style); + out([f2(x * k), f2((pageHeight - y) * k), f2(w * k), f2(-h * k), 're'].join(' ')); + + if (style !== null) { + out(getStyle(style)); + } + + return this; + }; + + /** + * Adds a triangle to PDF + * + * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name triangle + */ + API.triangle = function (x1, y1, x2, y2, x3, y3, style) { + this.lines([[x2 - x1, y2 - y1], // vector to point 2 + [x3 - x2, y3 - y2], // vector to point 3 + [x1 - x3, y1 - y3] // closing vector back to point 1 + ], x1, y1, // start of path + [1, 1], style, true); + return this; + }; + + /** + * Adds a rectangle with rounded corners to PDF + * + * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} w Width (in units declared at inception of PDF document) + * @param {Number} h Height (in units declared at inception of PDF document) + * @param {Number} rx Radius along x axis (in units declared at inception of PDF document) + * @param {Number} rx Radius along y axis (in units declared at inception of PDF document) + * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name roundedRect + */ + API.roundedRect = function (x, y, w, h, rx, ry, style) { + var MyArc = 4 / 3 * (Math.SQRT2 - 1); + this.lines([[w - 2 * rx, 0], [rx * MyArc, 0, rx, ry - ry * MyArc, rx, ry], [0, h - 2 * ry], [0, ry * MyArc, -(rx * MyArc), ry, -rx, ry], [-w + 2 * rx, 0], [-(rx * MyArc), 0, -rx, -(ry * MyArc), -rx, -ry], [0, -h + 2 * ry], [0, -(ry * MyArc), rx * MyArc, -ry, rx, -ry]], x + rx, y, // start of path + [1, 1], style); + return this; + }; + + /** + * Adds an ellipse to PDF + * + * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} rx Radius along x axis (in units declared at inception of PDF document) + * @param {Number} rx Radius along y axis (in units declared at inception of PDF document) + * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name ellipse + */ + API.ellipse = function (x, y, rx, ry, style) { + var lx = 4 / 3 * (Math.SQRT2 - 1) * rx, + ly = 4 / 3 * (Math.SQRT2 - 1) * ry; + + out([f2((x + rx) * k), f2((pageHeight - y) * k), 'm', f2((x + rx) * k), f2((pageHeight - (y - ly)) * k), f2((x + lx) * k), f2((pageHeight - (y - ry)) * k), f2(x * k), f2((pageHeight - (y - ry)) * k), 'c'].join(' ')); + out([f2((x - lx) * k), f2((pageHeight - (y - ry)) * k), f2((x - rx) * k), f2((pageHeight - (y - ly)) * k), f2((x - rx) * k), f2((pageHeight - y) * k), 'c'].join(' ')); + out([f2((x - rx) * k), f2((pageHeight - (y + ly)) * k), f2((x - lx) * k), f2((pageHeight - (y + ry)) * k), f2(x * k), f2((pageHeight - (y + ry)) * k), 'c'].join(' ')); + out([f2((x + lx) * k), f2((pageHeight - (y + ry)) * k), f2((x + rx) * k), f2((pageHeight - (y + ly)) * k), f2((x + rx) * k), f2((pageHeight - y) * k), 'c'].join(' ')); + + if (style !== null) { + out(getStyle(style)); + } + + return this; + }; + + /** + * Adds an circle to PDF + * + * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page + * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page + * @param {Number} r Radius (in units declared at inception of PDF document) + * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name circle + */ + API.circle = function (x, y, r, style) { + return this.ellipse(x, y, r, r, style); + }; + + /** + * Adds a properties to the PDF document + * + * @param {Object} A property_name-to-property_value object structure. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setProperties + */ + API.setProperties = function (properties) { + // copying only those properties we can render. + for (var property in documentProperties) { + if (documentProperties.hasOwnProperty(property) && properties[property]) { + documentProperties[property] = properties[property]; + } + } + return this; + }; + + /** + * Sets font size for upcoming text elements. + * + * @param {Number} size Font size in points. + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setFontSize + */ + API.setFontSize = function (size) { + activeFontSize = size; + return this; + }; + + /** + * Sets text font face, variant for upcoming text elements. + * See output of jsPDF.getFontList() for possible font names, styles. + * + * @param {String} fontName Font name or family. Example: "times" + * @param {String} fontStyle Font style or variant. Example: "italic" + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setFont + */ + API.setFont = function (fontName, fontStyle) { + activeFontKey = _getFont(fontName, fontStyle); + // if font is not found, the above line blows up and we never go further + return this; + }; + + /** + * Switches font style or variant for upcoming text elements, + * while keeping the font face or family same. + * See output of jsPDF.getFontList() for possible font names, styles. + * + * @param {String} style Font style or variant. Example: "italic" + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setFontStyle + */ + API.setFontStyle = API.setFontType = function (style) { + activeFontKey = _getFont(undefined, style); + // if font is not found, the above line blows up and we never go further + return this; + }; + + /** + * Returns an object - a tree of fontName to fontStyle relationships available to + * active PDF document. + * + * @public + * @function + * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... } + * @methodOf jsPDF# + * @name getFontList + */ + API.getFontList = function () { + // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added. + var list = {}, + fontName, + fontStyle, + tmp; + + for (fontName in fontmap) { + if (fontmap.hasOwnProperty(fontName)) { + list[fontName] = tmp = []; + for (fontStyle in fontmap[fontName]) { + if (fontmap[fontName].hasOwnProperty(fontStyle)) { + tmp.push(fontStyle); + } + } + } + } + + return list; + }; + + /** + * Add a custom font. + * + * @param {String} Postscript name of the Font. Example: "Menlo-Regular" + * @param {String} Name of font-family from @font-face definition. Example: "Menlo Regular" + * @param {String} Font style. Example: "normal" + * @function + * @returns the {fontKey} (same as the internal method) + * @methodOf jsPDF# + * @name addFont + */ + API.addFont = function (postScriptName, fontName, fontStyle) { + addFont(postScriptName, fontName, fontStyle, 'StandardEncoding'); + }; + + /** + * Sets line width for upcoming lines. + * + * @param {Number} width Line width (in units declared at inception of PDF document) + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setLineWidth + */ + API.setLineWidth = function (width) { + out((width * k).toFixed(2) + ' w'); + return this; + }; + + /** + * Sets the stroke color for upcoming elements. + * + * Depending on the number of arguments given, Gray, RGB, or CMYK + * color space is implied. + * + * When only ch1 is given, "Gray" color space is implied and it + * must be a value in the range from 0.00 (solid black) to to 1.00 (white) + * if values are communicated as String types, or in range from 0 (black) + * to 255 (white) if communicated as Number type. + * The RGB-like 0-255 range is provided for backward compatibility. + * + * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each + * value must be in the range from 0.00 (minimum intensity) to to 1.00 + * (max intensity) if values are communicated as String types, or + * from 0 (min intensity) to to 255 (max intensity) if values are communicated + * as Number types. + * The RGB-like 0-255 range is provided for backward compatibility. + * + * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each + * value must be a in the range from 0.00 (0% concentration) to to + * 1.00 (100% concentration) + * + * Because JavaScript treats fixed point numbers badly (rounds to + * floating point nearest to binary representation) it is highly advised to + * communicate the fractional numbers as String types, not JavaScript Number type. + * + * @param {Number|String} ch1 Color channel value + * @param {Number|String} ch2 Color channel value + * @param {Number|String} ch3 Color channel value + * @param {Number|String} ch4 Color channel value + * + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setDrawColor + */ + API.setDrawColor = function (ch1, ch2, ch3, ch4) { + var color; + if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) { + // Gray color space. + if (typeof ch1 === 'string') { + color = ch1 + ' G'; + } else { + color = f2(ch1 / 255) + ' G'; + } + } else if (ch4 === undefined) { + // RGB + if (typeof ch1 === 'string') { + color = [ch1, ch2, ch3, 'RG'].join(' '); + } else { + color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' '); + } + } else { + // CMYK + if (typeof ch1 === 'string') { + color = [ch1, ch2, ch3, ch4, 'K'].join(' '); + } else { + color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' '); + } + } + + out(color); + return this; + }; + + /** + * Sets the fill color for upcoming elements. + * + * Depending on the number of arguments given, Gray, RGB, or CMYK + * color space is implied. + * + * When only ch1 is given, "Gray" color space is implied and it + * must be a value in the range from 0.00 (solid black) to to 1.00 (white) + * if values are communicated as String types, or in range from 0 (black) + * to 255 (white) if communicated as Number type. + * The RGB-like 0-255 range is provided for backward compatibility. + * + * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each + * value must be in the range from 0.00 (minimum intensity) to to 1.00 + * (max intensity) if values are communicated as String types, or + * from 0 (min intensity) to to 255 (max intensity) if values are communicated + * as Number types. + * The RGB-like 0-255 range is provided for backward compatibility. + * + * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each + * value must be a in the range from 0.00 (0% concentration) to to + * 1.00 (100% concentration) + * + * Because JavaScript treats fixed point numbers badly (rounds to + * floating point nearest to binary representation) it is highly advised to + * communicate the fractional numbers as String types, not JavaScript Number type. + * + * @param {Number|String} ch1 Color channel value + * @param {Number|String} ch2 Color channel value + * @param {Number|String} ch3 Color channel value + * @param {Number|String} ch4 Color channel value + * + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setFillColor + */ + API.setFillColor = function (ch1, ch2, ch3, ch4) { + var color; + + if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) { + // Gray color space. + if (typeof ch1 === 'string') { + color = ch1 + ' g'; + } else { + color = f2(ch1 / 255) + ' g'; + } + } else if (ch4 === undefined || (typeof ch4 === 'undefined' ? 'undefined' : _typeof(ch4)) === 'object') { + // RGB + if (typeof ch1 === 'string') { + color = [ch1, ch2, ch3, 'rg'].join(' '); + } else { + color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' '); + } + if (ch4 && ch4.a === 0) { + //TODO Implement transparency. + //WORKAROUND use white for now + color = ['255', '255', '255', 'rg'].join(' '); + } + } else { + // CMYK + if (typeof ch1 === 'string') { + color = [ch1, ch2, ch3, ch4, 'k'].join(' '); + } else { + color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' '); + } + } + + out(color); + return this; + }; + + /** + * Sets the text color for upcoming elements. + * If only one, first argument is given, + * treats the value as gray-scale color value. + * + * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF' + * @param {Number} g Green channel color value in range 0-255 + * @param {Number} b Blue channel color value in range 0-255 + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setTextColor + */ + API.setTextColor = function (r, g, b) { + if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) { + var hex = parseInt(r.substr(1), 16); + r = hex >> 16 & 255; + g = hex >> 8 & 255; + b = hex & 255; + } + + if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') { + textColor = f3(r / 255) + ' g'; + } else { + textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' '); + } + return this; + }; + + /** + * Is an Object providing a mapping from human-readable to + * integer flag values designating the varieties of line cap + * and join styles. + * + * @returns {Object} + * @fieldOf jsPDF# + * @name CapJoinStyles + */ + API.CapJoinStyles = { + 0: 0, + 'butt': 0, + 'but': 0, + 'miter': 0, + 1: 1, + 'round': 1, + 'rounded': 1, + 'circle': 1, + 2: 2, + 'projecting': 2, + 'project': 2, + 'square': 2, + 'bevel': 2 + }; + + /** + * Sets the line cap styles + * See {jsPDF.CapJoinStyles} for variants + * + * @param {String|Number} style A string or number identifying the type of line cap + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setLineCap + */ + API.setLineCap = function (style) { + var id = this.CapJoinStyles[style]; + if (id === undefined) { + throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); + } + lineCapID = id; + out(id + ' J'); + + return this; + }; + + /** + * Sets the line join styles + * See {jsPDF.CapJoinStyles} for variants + * + * @param {String|Number} style A string or number identifying the type of line join + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name setLineJoin + */ + API.setLineJoin = function (style) { + var id = this.CapJoinStyles[style]; + if (id === undefined) { + throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); + } + lineJoinID = id; + out(id + ' j'); + + return this; + }; + + // Output is both an internal (for plugins) and external function + API.output = _output; + + /** + * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf') + * @param {String} filename The filename including extension. + * + * @function + * @returns {jsPDF} + * @methodOf jsPDF# + * @name save + */ + API.save = function (filename) { + API.output('save', filename); + }; + + // applying plugins (more methods) ON TOP of built-in API. + // this is intentional as we allow plugins to override + // built-ins + for (var plugin in jsPDF.API) { + if (jsPDF.API.hasOwnProperty(plugin)) { + if (plugin === 'events' && jsPDF.API.events.length) { + (function (events, newEvents) { + + // jsPDF.API.events is a JS Array of Arrays + // where each Array is a pair of event name, handler + // Events were added by plugins to the jsPDF instantiator. + // These are always added to the new instance and some ran + // during instantiation. + var eventname, handler_and_args, i; + + for (i = newEvents.length - 1; i !== -1; i--) { + // subscribe takes 3 args: 'topic', function, runonce_flag + // if undefined, runonce is false. + // users can attach callback directly, + // or they can attach an array with [callback, runonce_flag] + // that's what the "apply" magic is for below. + eventname = newEvents[i][0]; + handler_and_args = newEvents[i][1]; + events.subscribe.apply(events, [eventname].concat(typeof handler_and_args === 'function' ? [handler_and_args] : handler_and_args)); + } + })(events, jsPDF.API.events); + } else { + API[plugin] = jsPDF.API[plugin]; + } + } + } + + ////////////////////////////////////////////////////// + // continuing initialization of jsPDF Document object + ////////////////////////////////////////////////////// + // Add the first page automatically + addFonts(); + activeFontKey = 'F1'; + _addPage(format, orientation); + + events.publish('initialized'); + return API; + } + + /** + * jsPDF.API is a STATIC property of jsPDF class. + * jsPDF.API is an object you can add methods and properties to. + * The methods / properties you add will show up in new jsPDF objects. + * + * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics, + * callbacks to this object. These will be reassigned to all new instances of jsPDF. + * Examples: + * jsPDF.API.events['initialized'] = function(){ 'this' is API object } + * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object } + * + * @static + * @public + * @memberOf jsPDF + * @name API + * + * @example + * jsPDF.API.mymethod = function(){ + * // 'this' will be ref to internal API object. see jsPDF source + * // , so you can refer to built-in methods like so: + * // this.line(....) + * // this.text(....) + * } + * var pdfdoc = new jsPDF() + * pdfdoc.mymethod() // <- !!!!!! + */ + jsPDF.API = { + events: [] + }; + jsPDF.version = "1.x-master"; + + if (typeof define === 'function' && define.amd) { + define('jsPDF', function () { + return jsPDF; + }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = jsPDF; + } else { + global.jsPDF = jsPDF; + } + return jsPDF; +}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined); + + +/** + * jsPDF AcroForm Plugin + * Copyright (c) 2016 Alexander Weidt, https://github.com/BiggA94 + * + * Licensed under the MIT License. + * http://opensource.org/licenses/mit-license + */ + +(window.AcroForm = function (jsPDFAPI) { + 'use strict'; + + var AcroForm = window.AcroForm; + + AcroForm.scale = function (x) { + return x * (acroformPlugin.internal.scaleFactor / 1); // 1 = (96 / 72) + }; + AcroForm.antiScale = function (x) { + return 1 / acroformPlugin.internal.scaleFactor * x; + }; + + var acroformPlugin = { + fields: [], + xForms: [], + /** + * acroFormDictionaryRoot contains information about the AcroForm Dictionary + * 0: The Event-Token, the AcroFormDictionaryCallback has + * 1: The Object ID of the Root + */ + acroFormDictionaryRoot: null, + /** + * After the PDF gets evaluated, the reference to the root has to be reset, + * this indicates, whether the root has already been printed out + */ + printedOut: false, + internal: null + }; + + jsPDF.API.acroformPlugin = acroformPlugin; + + var annotReferenceCallback = function annotReferenceCallback() { + for (var i in this.acroformPlugin.acroFormDictionaryRoot.Fields) { + var formObject = this.acroformPlugin.acroFormDictionaryRoot.Fields[i]; + // add Annot Reference! + if (formObject.hasAnnotation) { + // If theres an Annotation Widget in the Form Object, put the Reference in the /Annot array + createAnnotationReference.call(this, formObject); + } + } + }; + + var createAcroForm = function createAcroForm() { + if (this.acroformPlugin.acroFormDictionaryRoot) { + //return; + throw new Error("Exception while creating AcroformDictionary"); + } + + // The Object Number of the AcroForm Dictionary + this.acroformPlugin.acroFormDictionaryRoot = new AcroForm.AcroFormDictionary(); + + this.acroformPlugin.internal = this.internal; + + // add Callback for creating the AcroForm Dictionary + this.acroformPlugin.acroFormDictionaryRoot._eventID = this.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback); + + this.internal.events.subscribe('buildDocument', annotReferenceCallback); //buildDocument + + // Register event, that is triggered when the DocumentCatalog is written, in order to add /AcroForm + this.internal.events.subscribe('putCatalog', putCatalogCallback); + + // Register event, that creates all Fields + this.internal.events.subscribe('postPutPages', createFieldCallback); + }; + + /** + * Create the Reference to the widgetAnnotation, so that it gets referenced in the Annot[] int the+ + * (Requires the Annotation Plugin) + */ + var createAnnotationReference = function createAnnotationReference(object) { + var options = { + type: 'reference', + object: object + }; + jsPDF.API.annotationPlugin.annotations[this.internal.getPageInfo(object.page).pageNumber].push(options); + }; + + var putForm = function putForm(formObject) { + if (this.acroformPlugin.printedOut) { + this.acroformPlugin.printedOut = false; + this.acroformPlugin.acroFormDictionaryRoot = null; + } + if (!this.acroformPlugin.acroFormDictionaryRoot) { + createAcroForm.call(this); + } + this.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject); + }; + + // Callbacks + + var putCatalogCallback = function putCatalogCallback() { + //Put reference to AcroForm to DocumentCatalog + if (typeof this.acroformPlugin.acroFormDictionaryRoot != 'undefined') { + // for safety, shouldn't normally be the case + this.internal.write('/AcroForm ' + this.acroformPlugin.acroFormDictionaryRoot.objId + ' ' + 0 + ' R'); + } else { + console.log('Root missing...'); + } + }; + + /** + * Adds /Acroform X 0 R to Document Catalog, + * and creates the AcroForm Dictionary + */ + var AcroFormDictionaryCallback = function AcroFormDictionaryCallback() { + // Remove event + this.internal.events.unsubscribe(this.acroformPlugin.acroFormDictionaryRoot._eventID); + + delete this.acroformPlugin.acroFormDictionaryRoot._eventID; + + this.acroformPlugin.printedOut = true; + }; + + /** + * Creates the single Fields and writes them into the Document + * + * If fieldArray is set, use the fields that are inside it instead of the fields from the AcroRoot + * (for the FormXObjects...) + */ + var createFieldCallback = function createFieldCallback(fieldArray) { + var standardFields = !fieldArray; + + if (!fieldArray) { + // in case there is no fieldArray specified, we want to print out the Fields of the AcroForm + // Print out Root + this.internal.newObjectDeferredBegin(this.acroformPlugin.acroFormDictionaryRoot.objId); + this.internal.out(this.acroformPlugin.acroFormDictionaryRoot.getString()); + } + + var fieldArray = fieldArray || this.acroformPlugin.acroFormDictionaryRoot.Kids; + + for (var i in fieldArray) { + var key = i; + var form = fieldArray[i]; + + var oldRect = form.Rect; + + if (form.Rect) { + form.Rect = AcroForm.internal.calculateCoordinates.call(this, form.Rect); + } + + // Start Writing the Object + this.internal.newObjectDeferredBegin(form.objId); + + var content = ""; + content += form.objId + " 0 obj\n"; + + content += "<<\n" + form.getContent(); + + form.Rect = oldRect; + + if (form.hasAppearanceStream && !form.appearanceStreamContent) { + // Calculate Appearance + var appearance = AcroForm.internal.calculateAppearanceStream.call(this, form); + content += "/AP << /N " + appearance + " >>\n"; + + this.acroformPlugin.xForms.push(appearance); + } + + // Assume AppearanceStreamContent is a Array with N,R,D (at least one of them!) + if (form.appearanceStreamContent) { + content += "/AP << "; + // Iterate over N,R and D + for (var k in form.appearanceStreamContent) { + var value = form.appearanceStreamContent[k]; + content += "/" + k + " "; + content += "<< "; + if (Object.keys(value).length >= 1 || Array.isArray(value)) { + // appearanceStream is an Array or Object! + for (var i in value) { + var obj = value[i]; + if (typeof obj === 'function') { + // if Function is referenced, call it in order to get the FormXObject + obj = obj.call(this, form); + } + content += "/" + i + " " + obj + " "; + + // In case the XForm is already used, e.g. OffState of CheckBoxes, don't add it + if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj); + } + } else { + var obj = value; + if (typeof obj === 'function') { + // if Function is referenced, call it in order to get the FormXObject + obj = obj.call(this, form); + } + content += "/" + i + " " + obj + " \n"; + if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj); + } + content += " >>\n"; + } + + // appearance stream is a normal Object.. + content += ">>\n"; + } + + content += ">>\nendobj\n"; + + this.internal.out(content); + } + if (standardFields) { + createXFormObjectCallback.call(this, this.acroformPlugin.xForms); + } + }; + + var createXFormObjectCallback = function createXFormObjectCallback(fieldArray) { + for (var i in fieldArray) { + var key = i; + var form = fieldArray[i]; + // Start Writing the Object + this.internal.newObjectDeferredBegin(form && form.objId); + + var content = ""; + content += form ? form.getString() : ''; + this.internal.out(content); + + delete fieldArray[key]; + } + }; + + // Public: + + jsPDFAPI.addField = function (fieldObject) { + //var opt = parseOptions(fieldObject); + if (fieldObject instanceof AcroForm.TextField) { + addTextField.call(this, fieldObject); + } else if (fieldObject instanceof AcroForm.ChoiceField) { + addChoiceField.call(this, fieldObject); + } else if (fieldObject instanceof AcroForm.Button) { + addButton.call(this, fieldObject); + } else if (fieldObject instanceof AcroForm.ChildClass) { + putForm.call(this, fieldObject); + } else if (fieldObject) { + // try to put.. + putForm.call(this, fieldObject); + } + fieldObject.page = this.acroformPlugin.internal.getCurrentPageInfo().pageNumber; + return this; + }; + + // ############### sort in: + + /** + * Button + * FT = Btn + */ + var addButton = function addButton(options) { + var options = options || new AcroForm.Field(); + + options.FT = '/Btn'; + + /** + * Calculating the Ff entry: + * + * The Ff entry contains flags, that have to be set bitwise + * In the Following the number in the Comment is the BitPosition + */ + var flags = options.Ff || 0; + + // 17, Pushbutton + if (options.pushbutton) { + // Options.pushbutton should be 1 or 0 + flags = AcroForm.internal.setBitPosition(flags, 17); + delete options.pushbutton; + } + + //16, Radio + if (options.radio) { + //flags = options.Ff | options.radio << 15; + flags = AcroForm.internal.setBitPosition(flags, 16); + delete options.radio; + } + + // 15, NoToggleToOff (Radio buttons only + if (options.noToggleToOff) { + //flags = options.Ff | options.noToggleToOff << 14; + flags = AcroForm.internal.setBitPosition(flags, 15); + //delete options.noToggleToOff; + } + + // In case, there is no Flag set, it is a check-box + options.Ff = flags; + + putForm.call(this, options); + }; + + var addTextField = function addTextField(options) { + var options = options || new AcroForm.Field(); + + options.FT = '/Tx'; + + /** + * Calculating the Ff entry: + * + * The Ff entry contains flags, that have to be set bitwise + * In the Following the number in the Comment is the BitPosition + */ + + var flags = options.Ff || 0; + + // 13, multiline + if (options.multiline) { + // Set Flag + flags = flags | 1 << 12; + // Remove multiline from FieldObject + //delete options.multiline; + } + + // 14, Password + if (options.password) { + flags = flags | 1 << 13; + //delete options.password; + } + + // 21, FileSelect, PDF 1.4... + if (options.fileSelect) { + flags = flags | 1 << 20; + //delete options.fileSelect; + } + + // 23, DoNotSpellCheck, PDF 1.4... + if (options.doNotSpellCheck) { + flags = flags | 1 << 22; + //delete options.doNotSpellCheck; + } + + // 24, DoNotScroll, PDF 1.4... + if (options.doNotScroll) { + flags = flags | 1 << 23; + //delete options.doNotScroll; + } + + options.Ff = options.Ff || flags; + + // Add field + putForm.call(this, options); + }; + + var addChoiceField = function addChoiceField(opt) { + var options = opt || new AcroForm.Field(); + + options.FT = '/Ch'; + + /** + * Calculating the Ff entry: + * + * The Ff entry contains flags, that have to be set bitwise + * In the Following the number in the Comment is the BitPosition + */ + + var flags = options.Ff || 0; + + // 18, Combo (If not set, the choiceField is a listBox!!) + if (options.combo) { + // Set Flag + flags = AcroForm.internal.setBitPosition(flags, 18); + // Remove combo from FieldObject + delete options.combo; + } + + // 19, Edit + if (options.edit) { + flags = AcroForm.internal.setBitPosition(flags, 19); + delete options.edit; + } + + // 20, Sort + if (options.sort) { + flags = AcroForm.internal.setBitPosition(flags, 20); + delete options.sort; + } + + // 22, MultiSelect (PDF 1.4) + if (options.multiSelect && this.internal.getPDFVersion() >= 1.4) { + flags = AcroForm.internal.setBitPosition(flags, 22); + delete options.multiSelect; + } + + // 23, DoNotSpellCheck (PDF 1.4) + if (options.doNotSpellCheck && this.internal.getPDFVersion() >= 1.4) { + flags = AcroForm.internal.setBitPosition(flags, 23); + delete options.doNotSpellCheck; + } + + options.Ff = flags; + + //options.hasAnnotation = true; + + // Add field + putForm.call(this, options); + }; +})(jsPDF.API); + +var AcroForm = window.AcroForm; + +AcroForm.internal = {}; + +AcroForm.createFormXObject = function (formObject) { + var xobj = new AcroForm.FormXObject(); + var height = AcroForm.Appearance.internal.getHeight(formObject) || 0; + var width = AcroForm.Appearance.internal.getWidth(formObject) || 0; + xobj.BBox = [0, 0, width, height]; + return xobj; +}; + +// Contains Methods for creating standard appearances +AcroForm.Appearance = { + CheckBox: { + createAppearanceStream: function createAppearanceStream() { + var appearance = { + N: { + On: AcroForm.Appearance.CheckBox.YesNormal + }, + D: { + On: AcroForm.Appearance.CheckBox.YesPushDown, + Off: AcroForm.Appearance.CheckBox.OffPushDown + } + }; + + return appearance; + }, + /** + * If any other icons are needed, the number between the brackets can be changed + * @returns {string} + */ + createMK: function createMK() { + // 3-> Hook + return "<< /CA (3)>>"; + }, + /** + * Returns the standard On Appearance for a CheckBox + * @returns {AcroForm.FormXObject} + */ + YesPushDown: function YesPushDown(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + // F13 is ZapfDingbats (Symbolic) + formObject.Q = 1; // set text-alignment as centered + var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", 50); + stream += "0.749023 g\n\ + 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ + f\n\ + BMC\n\ + q\n\ + 0 0 1 rg\n\ + /F13 " + calcRes.fontSize + " Tf 0 g\n\ + BT\n"; + stream += calcRes.text; + stream += "ET\n\ + Q\n\ + EMC\n"; + xobj.stream = stream; + return xobj; + }, + + YesNormal: function YesNormal(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + formObject.Q = 1; // set text-alignment as centered + var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", AcroForm.Appearance.internal.getHeight(formObject) * 0.9); + stream += "1 g\n\ +0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ +f\n\ +q\n\ +0 0 1 rg\n\ +0 0 " + (AcroForm.Appearance.internal.getWidth(formObject) - 1) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 1) + " re\n\ +W\n\ +n\n\ +0 g\n\ +BT\n\ +/F13 " + calcRes.fontSize + " Tf 0 g\n"; + stream += calcRes.text; + stream += "ET\n\ + Q\n"; + xobj.stream = stream; + return xobj; + }, + + /** + * Returns the standard Off Appearance for a CheckBox + * @returns {AcroForm.FormXObject} + */ + OffPushDown: function OffPushDown(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + stream += "0.749023 g\n\ + 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ + f\n"; + xobj.stream = stream; + return xobj; + } + }, + + RadioButton: { + Circle: { + createAppearanceStream: function createAppearanceStream(name) { + var appearanceStreamContent = { + D: { + 'Off': AcroForm.Appearance.RadioButton.Circle.OffPushDown + }, + N: {} + }; + appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Circle.YesNormal; + appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Circle.YesPushDown; + return appearanceStreamContent; + }, + createMK: function createMK() { + return "<< /CA (l)>>"; + }, + + YesNormal: function YesNormal(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + // Make the Radius of the Circle relative to min(height, width) of formObject + var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4; + // The Borderpadding... + DotRadius *= 0.9; + var c = AcroForm.Appearance.internal.Bezier_C; + /* + The Following is a Circle created with Bezier-Curves. + */ + stream += "q\n\ +1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ +" + DotRadius + " 0 m\n\ +" + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\ +-" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\ +-" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\ +" + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\ +f\n\ +Q\n"; + xobj.stream = stream; + return xobj; + }, + YesPushDown: function YesPushDown(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4; + // The Borderpadding... + DotRadius *= 0.9; + // Save results for later use; no need to waste processor ticks on doing math + var k = DotRadius * 2; + // var c = AcroForm.Appearance.internal.Bezier_C; + var kc = k * AcroForm.Appearance.internal.Bezier_C; + var dc = DotRadius * AcroForm.Appearance.internal.Bezier_C; + // stream += "0.749023 g\n\ + // q\n\ + // 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ + // " + DotRadius * 2 + " 0 m\n\ + // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\ + // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\ + // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\ + // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\ + // f\n\ + // Q\n\ + // 0 g\n\ + // q\n\ + // 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ + // " + DotRadius + " 0 m\n\ + // " + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\ + // -" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\ + // -" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\ + // " + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\ + // f\n\ + // Q\n"; + + // FASTER VERSION with less processor ticks spent on math operations + stream += "0.749023 g\n\ + q\n\ + 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ +" + k + " 0 m\n\ +" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\ +-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\ +-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\ +" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\ + f\n\ + Q\n\ + 0 g\n\ + q\n\ + 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ +" + DotRadius + " 0 m\n\ +" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c\n\ +-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c\n\ +-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c\n\ +" + dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c\n\ + f\n\ + Q\n"; + xobj.stream = stream; + return xobj; + }, + OffPushDown: function OffPushDown(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4; + // The Borderpadding... + DotRadius *= 0.9; + // Save results for later use; no need to waste processor ticks on doing math + var k = DotRadius * 2; + // var c = AcroForm.Appearance.internal.Bezier_C; + var kc = k * AcroForm.Appearance.internal.Bezier_C; + // stream += "0.749023 g\n\ + // q\n\ + // 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ + // " + DotRadius * 2 + " 0 m\n\ + // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\ + // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\ + // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\ + // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\ + // f\n\ + // Q\n"; + + // FASTER VERSION with less processor ticks spent on math operations + stream += "0.749023 g\n\ + q\n\ + 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ +" + k + " 0 m\n\ +" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\ +-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\ +-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\ +" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\ + f\n\ + Q\n"; + xobj.stream = stream; + return xobj; + } + }, + + Cross: { + /** + * Creates the Actual AppearanceDictionary-References + * @param name + * @returns + */ + createAppearanceStream: function createAppearanceStream(name) { + var appearanceStreamContent = { + D: { + 'Off': AcroForm.Appearance.RadioButton.Cross.OffPushDown + }, + N: {} + }; + appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Cross.YesNormal; + appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Cross.YesPushDown; + return appearanceStreamContent; + }, + createMK: function createMK() { + return "<< /CA (8)>>"; + }, + + YesNormal: function YesNormal(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + var cross = AcroForm.Appearance.internal.calculateCross(formObject); + stream += "q\n\ + 1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\ + W\n\ + n\n\ + " + cross.x1.x + " " + cross.x1.y + " m\n\ + " + cross.x2.x + " " + cross.x2.y + " l\n\ + " + cross.x4.x + " " + cross.x4.y + " m\n\ + " + cross.x3.x + " " + cross.x3.y + " l\n\ + s\n\ + Q\n"; + xobj.stream = stream; + return xobj; + }, + YesPushDown: function YesPushDown(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var cross = AcroForm.Appearance.internal.calculateCross(formObject); + var stream = ""; + stream += "0.749023 g\n\ + 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ + f\n\ + q\n\ + 1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\ + W\n\ + n\n\ + " + cross.x1.x + " " + cross.x1.y + " m\n\ + " + cross.x2.x + " " + cross.x2.y + " l\n\ + " + cross.x4.x + " " + cross.x4.y + " m\n\ + " + cross.x3.x + " " + cross.x3.y + " l\n\ + s\n\ + Q\n"; + xobj.stream = stream; + return xobj; + }, + OffPushDown: function OffPushDown(formObject) { + var xobj = AcroForm.createFormXObject(formObject); + var stream = ""; + stream += "0.749023 g\n\ + 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ + f\n"; + xobj.stream = stream; + return xobj; + } + } + }, + + /** + * Returns the standard Appearance + * @returns {AcroForm.FormXObject} + */ + createDefaultAppearanceStream: function createDefaultAppearanceStream(formObject) { + var stream = ""; + // Set Helvetica to Standard Font (size: auto) + // Color: Black + stream += "/Helv 0 Tf 0 g"; + return stream; + } +}; + +AcroForm.Appearance.internal = { + Bezier_C: 0.551915024494, + + calculateCross: function calculateCross(formObject) { + var min = function min(x, y) { + return x > y ? y : x; + }; + + var width = AcroForm.Appearance.internal.getWidth(formObject); + var height = AcroForm.Appearance.internal.getHeight(formObject); + var a = min(width, height); + var crossSize = a; + var borderPadding = 2; // The Padding in px + + + var cross = { + x1: { // upperLeft + x: (width - a) / 2, + y: (height - a) / 2 + a }, + x2: { // lowerRight + x: (width - a) / 2 + a, + y: (height - a) / 2 //borderPadding + }, + x3: { // lowerLeft + x: (width - a) / 2, + y: (height - a) / 2 //borderPadding + }, + x4: { // upperRight + x: (width - a) / 2 + a, + y: (height - a) / 2 + a } + }; + + return cross; + } +}; +AcroForm.Appearance.internal.getWidth = function (formObject) { + return formObject.Rect[2]; //(formObject.Rect[2] - formObject.Rect[0]) || 0; +}; +AcroForm.Appearance.internal.getHeight = function (formObject) { + return formObject.Rect[3]; //(formObject.Rect[1] - formObject.Rect[3]) || 0; +}; + +// ########################## + +//### For inheritance: +AcroForm.internal.inherit = function (child, parent) { + var ObjectCreate = Object.create || function (o) { + var F = function F() {}; + F.prototype = o; + return new F(); + }; + child.prototype = Object.create(parent.prototype); + child.prototype.constructor = child; +}; + +// ### Handy Functions: + +AcroForm.internal.arrayToPdfArray = function (array) { + if (Array.isArray(array)) { + var content = ' ['; + for (var i in array) { + var element = array[i].toString(); + content += element; + content += i < array.length - 1 ? ' ' : ''; + } + content += ']'; + + return content; + } +}; + +AcroForm.internal.toPdfString = function (string) { + string = string || ""; + + // put Bracket at the Beginning of the String + if (string.indexOf('(') !== 0) { + string = '(' + string; + } + + if (string.substring(string.length - 1) != ')') { + string += '('; + } + return string; +}; + +// ########################## +// Classes +// ########################## + + +AcroForm.PDFObject = function () { + // The Object ID in the PDF Object Model + // todo + var _objId; + Object.defineProperty(this, 'objId', { + get: function get() { + if (!_objId) { + if (this.internal) { + _objId = this.internal.newObjectDeferred(); + } else if (jsPDF.API.acroformPlugin.internal) { + // todo - find better option, that doesn't rely on a Global Static var + _objId = jsPDF.API.acroformPlugin.internal.newObjectDeferred(); + } + } + if (!_objId) { + console.log("Couldn't create Object ID"); + } + return _objId; + }, + configurable: false + }); +}; + +AcroForm.PDFObject.prototype.toString = function () { + return this.objId + " 0 R"; +}; + +AcroForm.PDFObject.prototype.getString = function () { + var res = this.objId + " 0 obj\n<<"; + var content = this.getContent(); + + res += content + ">>\n"; + if (this.stream) { + res += "stream\n"; + res += this.stream; + res += "endstream\n"; + } + res += "endobj\n"; + return res; +}; + +AcroForm.PDFObject.prototype.getContent = function () { + /** + * Prints out all enumerable Variables from the Object + * @param fieldObject + * @returns {string} + */ + var createContentFromFieldObject = function createContentFromFieldObject(fieldObject) { + var content = ''; + + var keys = Object.keys(fieldObject).filter(function (key) { + return key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_"; + }); + + for (var i in keys) { + var key = keys[i]; + var value = fieldObject[key]; + + /*if (key == 'Rect' && value) { + value = AcroForm.internal.calculateCoordinates.call(jsPDF.API.acroformPlugin.internal, value); + }*/ + + if (value) { + if (Array.isArray(value)) { + content += '/' + key + ' ' + AcroForm.internal.arrayToPdfArray(value) + "\n"; + } else if (value instanceof AcroForm.PDFObject) { + // In case it is a reference to another PDFObject, take the referennce number + content += '/' + key + ' ' + value.objId + " 0 R" + "\n"; + } else { + content += '/' + key + ' ' + value + '\n'; + } + } + } + return content; + }; + + var object = ""; + + object += createContentFromFieldObject(this); + return object; +}; + +AcroForm.FormXObject = function () { + AcroForm.PDFObject.call(this); + this.Type = "/XObject"; + this.Subtype = "/Form"; + this.FormType = 1; + this.BBox; + this.Matrix; + this.Resources = "2 0 R"; + this.PieceInfo; + var _stream; + Object.defineProperty(this, 'Length', { + enumerable: true, + get: function get() { + return _stream !== undefined ? _stream.length : 0; + } + }); + Object.defineProperty(this, 'stream', { + enumerable: false, + set: function set(val) { + _stream = val; + }, + get: function get() { + if (_stream) { + return _stream; + } else { + return null; + } + } + }); +}; + +AcroForm.internal.inherit(AcroForm.FormXObject, AcroForm.PDFObject); + +AcroForm.AcroFormDictionary = function () { + AcroForm.PDFObject.call(this); + var _Kids = []; + Object.defineProperty(this, 'Kids', { + enumerable: false, + configurable: true, + get: function get() { + if (_Kids.length > 0) { + return _Kids; + } else { + return; + } + } + }); + Object.defineProperty(this, 'Fields', { + enumerable: true, + configurable: true, + get: function get() { + return _Kids; + } + }); + // Default Appearance + this.DA; +}; + +AcroForm.internal.inherit(AcroForm.AcroFormDictionary, AcroForm.PDFObject); + +// ##### The Objects, the User can Create: + + +// The Field Object contains the Variables, that every Field needs +// Rectangle for Appearance: lower_left_X, lower_left_Y, width, height +AcroForm.Field = function () { + 'use strict'; + + AcroForm.PDFObject.call(this); + + var _Rect; + Object.defineProperty(this, 'Rect', { + enumerable: true, + configurable: false, + get: function get() { + if (!_Rect) { + return; + } + var tmp = _Rect; + //var calculatedRes = AcroForm.internal.calculateCoordinates(_Rect); // do later! + return tmp; + }, + set: function set(val) { + _Rect = val; + } + }); + + var _FT = ""; + Object.defineProperty(this, 'FT', { + enumerable: true, + set: function set(val) { + _FT = val; + }, + get: function get() { + return _FT; + } + }); + /** + * The Partial name of the Field Object. + * It has to be unique. + */ + var _T; + + Object.defineProperty(this, 'T', { + enumerable: true, + configurable: false, + set: function set(val) { + _T = val; + }, + get: function get() { + if (!_T || _T.length < 1) { + if (this instanceof AcroForm.ChildClass) { + // In case of a Child from a Radio´Group, you don't need a FieldName!!! + return; + } + return "(FieldObject" + AcroForm.Field.FieldNum++ + ")"; + } + if (_T.substring(0, 1) == "(" && _T.substring(_T.length - 1)) { + return _T; + } + return "(" + _T + ")"; + } + }); + + var _DA; + // Defines the default appearance (Needed for variable Text) + Object.defineProperty(this, 'DA', { + enumerable: true, + get: function get() { + if (!_DA) { + return; + } + return '(' + _DA + ')'; + }, + set: function set(val) { + _DA = val; + } + }); + + var _DV; + // Defines the default value + Object.defineProperty(this, 'DV', { + enumerable: true, + configurable: true, + get: function get() { + if (!_DV) { + return; + } + return _DV; + }, + set: function set(val) { + _DV = val; + } + }); + + //this.Type = "/Annot"; + //this.Subtype = "/Widget"; + Object.defineProperty(this, 'Type', { + enumerable: true, + get: function get() { + return this.hasAnnotation ? "/Annot" : null; + } + }); + + Object.defineProperty(this, 'Subtype', { + enumerable: true, + get: function get() { + return this.hasAnnotation ? "/Widget" : null; + } + }); + + /** + * + * @type {Array} + */ + this.BG; + + Object.defineProperty(this, 'hasAnnotation', { + enumerable: false, + get: function get() { + if (this.Rect || this.BC || this.BG) { + return true; + } + return false; + } + }); + + Object.defineProperty(this, 'hasAppearanceStream', { + enumerable: false, + configurable: true, + writable: true + }); + + Object.defineProperty(this, 'page', { + enumerable: false, + configurable: true, + writable: true + }); +}; +AcroForm.Field.FieldNum = 0; + +AcroForm.internal.inherit(AcroForm.Field, AcroForm.PDFObject); + +AcroForm.ChoiceField = function () { + AcroForm.Field.call(this); + // Field Type = Choice Field + this.FT = "/Ch"; + // options + this.Opt = []; + this.V = '()'; + // Top Index + this.TI = 0; + /** + * Defines, whether the + * @type {boolean} + */ + this.combo = false; + /** + * Defines, whether the Choice Field is an Edit Field. + * An Edit Field is automatically an Combo Field. + */ + Object.defineProperty(this, 'edit', { + enumerable: true, + set: function set(val) { + if (val == true) { + this._edit = true; + // ComboBox has to be true + this.combo = true; + } else { + this._edit = false; + } + }, + get: function get() { + if (!this._edit) { + return false; + } + return this._edit; + }, + configurable: false + }); + this.hasAppearanceStream = true; + Object.defineProperty(this, 'V', { + get: function get() { + AcroForm.internal.toPdfString(); + } + }); +}; +AcroForm.internal.inherit(AcroForm.ChoiceField, AcroForm.Field); +window["ChoiceField"] = AcroForm.ChoiceField; + +AcroForm.ListBox = function () { + AcroForm.ChoiceField.call(this); + //var combo = true; +}; +AcroForm.internal.inherit(AcroForm.ListBox, AcroForm.ChoiceField); +window["ListBox"] = AcroForm.ListBox; + +AcroForm.ComboBox = function () { + AcroForm.ListBox.call(this); + this.combo = true; +}; +AcroForm.internal.inherit(AcroForm.ComboBox, AcroForm.ListBox); +window["ComboBox"] = AcroForm.ComboBox; + +AcroForm.EditBox = function () { + AcroForm.ComboBox.call(this); + this.edit = true; +}; +AcroForm.internal.inherit(AcroForm.EditBox, AcroForm.ComboBox); +window["EditBox"] = AcroForm.EditBox; + +AcroForm.Button = function () { + AcroForm.Field.call(this); + this.FT = "/Btn"; + //this.hasAnnotation = true; +}; +AcroForm.internal.inherit(AcroForm.Button, AcroForm.Field); +window["Button"] = AcroForm.Button; + +AcroForm.PushButton = function () { + AcroForm.Button.call(this); + this.pushbutton = true; +}; +AcroForm.internal.inherit(AcroForm.PushButton, AcroForm.Button); +window["PushButton"] = AcroForm.PushButton; + +AcroForm.RadioButton = function () { + AcroForm.Button.call(this); + this.radio = true; + var _Kids = []; + Object.defineProperty(this, 'Kids', { + enumerable: true, + get: function get() { + if (_Kids.length > 0) { + return _Kids; + } + } + }); + + Object.defineProperty(this, '__Kids', { + get: function get() { + return _Kids; + } + }); + + var _noToggleToOff; + + Object.defineProperty(this, 'noToggleToOff', { + enumerable: false, + get: function get() { + return _noToggleToOff; + }, + set: function set(val) { + _noToggleToOff = val; + } + }); + + //this.hasAnnotation = false; +}; +AcroForm.internal.inherit(AcroForm.RadioButton, AcroForm.Button); +window["RadioButton"] = AcroForm.RadioButton; + +/* + * The Child classs of a RadioButton (the radioGroup) + * -> The single Buttons + */ +AcroForm.ChildClass = function (parent, name) { + AcroForm.Field.call(this); + this.Parent = parent; + + // todo: set AppearanceType as variable that can be set from the outside... + this._AppearanceType = AcroForm.Appearance.RadioButton.Circle; // The Default appearanceType is the Circle + this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name); + + // Set Print in the Annot Flag + this.F = AcroForm.internal.setBitPosition(this.F, 3, 1); + + // Set AppearanceCharacteristicsDictionary with default appearance if field is not interacting with user + this.MK = this._AppearanceType.createMK(); // (8) -> Cross, (1)-> Circle, ()-> nothing + + // Default Appearance is Off + this.AS = "/Off"; // + name; + + this._Name = name; +}; +AcroForm.internal.inherit(AcroForm.ChildClass, AcroForm.Field); + +AcroForm.RadioButton.prototype.setAppearance = function (appearance) { + if (!('createAppearanceStream' in appearance && 'createMK' in appearance)) { + console.log("Couldn't assign Appearance to RadioButton. Appearance was Invalid!"); + return; + } + for (var i in this.__Kids) { + var child = this.__Kids[i]; + + child.appearanceStreamContent = appearance.createAppearanceStream(child._Name); + child.MK = appearance.createMK(); + } +}; + +AcroForm.RadioButton.prototype.createOption = function (name) { + var parent = this; + var kidCount = this.__Kids.length; + + // Create new Child for RadioGroup + var child = new AcroForm.ChildClass(parent, name); + // Add to Parent + this.__Kids.push(child); + + jsPDF.API.addField(child); + + return child; +}; + +AcroForm.CheckBox = function () { + Button.call(this); + this.appearanceStreamContent = AcroForm.Appearance.CheckBox.createAppearanceStream(); + this.MK = AcroForm.Appearance.CheckBox.createMK(); + this.AS = "/On"; + this.V = "/On"; +}; +AcroForm.internal.inherit(AcroForm.CheckBox, AcroForm.Button); +window["CheckBox"] = AcroForm.CheckBox; + +AcroForm.TextField = function () { + AcroForm.Field.call(this); + this.DA = AcroForm.Appearance.createDefaultAppearanceStream(); + this.F = 4; + var _V; + Object.defineProperty(this, 'V', { + get: function get() { + if (_V) { + return "(" + _V + ")"; + } else { + return _V; + } + }, + enumerable: true, + set: function set(val) { + _V = val; + } + }); + + var _DV; + Object.defineProperty(this, 'DV', { + get: function get() { + if (_DV) { + return "(" + _DV + ")"; + } else { + return _DV; + } + }, + enumerable: true, + set: function set(val) { + _DV = val; + } + }); + + var _multiline = false; + Object.defineProperty(this, 'multiline', { + enumerable: false, + get: function get() { + return _multiline; + }, + set: function set(val) { + _multiline = val; + } + }); + + //this.multiline = false; + //this.password = false; + /** + * For PDF 1.4 + * @type {boolean} + */ + //this.fileSelect = false; + /** + * For PDF 1.4 + * @type {boolean} + */ + //this.doNotSpellCheck = false; + /** + * For PDF 1.4 + * @type {boolean} + */ + //this.doNotScroll = false; + + var _MaxLen = false; + Object.defineProperty(this, 'MaxLen', { + enumerable: true, + get: function get() { + return _MaxLen; + }, + set: function set(val) { + _MaxLen = val; + } + }); + + Object.defineProperty(this, 'hasAppearanceStream', { + enumerable: false, + get: function get() { + return this.V || this.DV; + } + }); +}; +AcroForm.internal.inherit(AcroForm.TextField, AcroForm.Field); +window["TextField"] = AcroForm.TextField; + +AcroForm.PasswordField = function () { + TextField.call(this); + Object.defineProperty(this, 'password', { + value: true, + enumerable: false, + configurable: false, + writable: false + }); +}; +AcroForm.internal.inherit(AcroForm.PasswordField, AcroForm.TextField); +window["PasswordField"] = AcroForm.PasswordField; + +// ############ internal functions + +/* + * small workaround for calculating the TextMetric approximately + * @param text + * @param fontsize + * @returns {TextMetrics} (Has Height and Width) + */ +AcroForm.internal.calculateFontSpace = function (text, fontsize, fonttype) { + var fonttype = fonttype || "helvetica"; + //re-use canvas object for speed improvements + var canvas = AcroForm.internal.calculateFontSpace.canvas || (AcroForm.internal.calculateFontSpace.canvas = document.createElement('canvas')); + + var context = canvas.getContext('2d'); + context.save(); + var newFont = fontsize + " " + fonttype; + context.font = newFont; + var res = context.measureText(text); + context.fontcolor = 'black'; + // Calculate height: + var context = canvas.getContext('2d'); + res.height = context.measureText("3").width * 1.5; // 3 because in ZapfDingbats its a Hook and a 3 in normal fonts + context.restore(); + + var width = res.width; + + return res; +}; + +AcroForm.internal.calculateX = function (formObject, text, font, maxFontSize) { + var maxFontSize = maxFontSize || 12; + var font = font || "helvetica"; + var returnValue = { + text: "", + fontSize: "" + }; + // Remove Brackets + text = text.substr(0, 1) == '(' ? text.substr(1) : text; + text = text.substr(text.length - 1) == ')' ? text.substr(0, text.length - 1) : text; + // split into array of words + var textSplit = text.split(' '); + + /** + * the color could be ((alpha)||(r,g,b)||(c,m,y,k)) + * @type {string} + */ + var color = "0 g\n"; + var fontSize = maxFontSize; // The Starting fontSize (The Maximum) + var lineSpacing = 2; + var borderPadding = 2; + + var height = AcroForm.Appearance.internal.getHeight(formObject) || 0; + height = height < 0 ? -height : height; + var width = AcroForm.Appearance.internal.getWidth(formObject) || 0; + width = width < 0 ? -width : width; + + var isSmallerThanWidth = function isSmallerThanWidth(i, lastLine, fontSize) { + if (i + 1 < textSplit.length) { + var tmp = lastLine + " " + textSplit[i + 1]; + var TextWidth = AcroForm.internal.calculateFontSpace(tmp, fontSize + "px", font).width; + var FieldWidth = width - 2 * borderPadding; + return TextWidth <= FieldWidth; + } else { + return false; + } + }; + + fontSize++; + FontSize: while (true) { + var text = ""; + fontSize--; + var textHeight = AcroForm.internal.calculateFontSpace("3", fontSize + "px", font).height; + var startY = formObject.multiline ? height - fontSize : (height - textHeight) / 2; + startY += lineSpacing; + var startX = -borderPadding; + + var lastX = startX, + lastY = startY; + var firstWordInLine = 0, + lastWordInLine = 0; + var lastLength = 0; + + var y = 0; + if (fontSize == 0) { + // In case, the Text doesn't fit at all + fontSize = 12; + text = "(...) Tj\n"; + text += "% Width of Text: " + AcroForm.internal.calculateFontSpace(text, "1px").width + ", FieldWidth:" + width + "\n"; + break; + } + + lastLength = AcroForm.internal.calculateFontSpace(textSplit[0] + " ", fontSize + "px", font).width; + + var lastLine = ""; + var lineCount = 0; + Line: for (var i in textSplit) { + lastLine += textSplit[i] + " "; + // Remove last blank + lastLine = lastLine.substr(lastLine.length - 1) == " " ? lastLine.substr(0, lastLine.length - 1) : lastLine; + var key = parseInt(i); + lastLength = AcroForm.internal.calculateFontSpace(lastLine + " ", fontSize + "px", font).width; + var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize); + var isLastWord = i >= textSplit.length - 1; + if (nextLineIsSmaller && !isLastWord) { + lastLine += " "; + continue; // Line + } else if (!nextLineIsSmaller && !isLastWord) { + if (!formObject.multiline) { + continue FontSize; + } else { + if ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) { + // If the Text is higher than the FieldObject + continue FontSize; + } + lastWordInLine = key; + // go on + } + } else if (isLastWord) { + lastWordInLine = key; + } else { + if (formObject.multiline && (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) { + // If the Text is higher than the FieldObject + continue FontSize; + } + } + + var line = ''; + + for (var x = firstWordInLine; x <= lastWordInLine; x++) { + line += textSplit[x] + ' '; + } + + // Remove last blank + line = line.substr(line.length - 1) == " " ? line.substr(0, line.length - 1) : line; + //lastLength -= blankSpace.width; + lastLength = AcroForm.internal.calculateFontSpace(line, fontSize + "px", font).width; + + // Calculate startX + switch (formObject.Q) { + case 2: + // Right justified + startX = width - lastLength - borderPadding; + break; + case 1: + // Q = 1 := Text-Alignment: Center + startX = (width - lastLength) / 2; + break; + case 0: + default: + startX = borderPadding; + break; + } + text += startX + ' ' + lastY + ' Td\n'; + text += '(' + line + ') Tj\n'; + // reset X in PDF + text += -startX + ' 0 Td\n'; + + // After a Line, adjust y position + lastY = -(fontSize + lineSpacing); + lastX = startX; + + // Reset for next iteration step + lastLength = 0; + firstWordInLine = lastWordInLine + 1; + lineCount++; + + lastLine = ""; + continue Line; + } + break; + } + + returnValue.text = text; + returnValue.fontSize = fontSize; + + return returnValue; +}; + +AcroForm.internal.calculateAppearanceStream = function (formObject) { + if (formObject.appearanceStreamContent) { + // If appearanceStream is already set, use it + return formObject.appearanceStreamContent; + } + + if (!formObject.V && !formObject.DV) { + return; + } + + // else calculate it + + var stream = ''; + + var text = formObject.V || formObject.DV; + + var calcRes = AcroForm.internal.calculateX(formObject, text); + + stream += '/Tx BMC\n' + 'q\n' + + //color + '\n' + + '/F1 ' + calcRes.fontSize + ' Tf\n' + + // Text Matrix + '1 0 0 1 0 0 Tm\n'; + // Begin Text + stream += 'BT\n'; + stream += calcRes.text; + // End Text + stream += 'ET\n'; + stream += 'Q\n' + 'EMC\n'; + + var appearanceStreamContent = new AcroForm.createFormXObject(formObject); + + appearanceStreamContent.stream = stream; + + var appearance = { + N: { + 'Normal': appearanceStreamContent + } + }; + + return appearanceStreamContent; +}; + +/* + * Converts the Parameters from x,y,w,h to lowerLeftX, lowerLeftY, upperRightX, upperRightY + * @param x + * @param y + * @param w + * @param h + * @returns {*[]} + */ +AcroForm.internal.calculateCoordinates = function (x, y, w, h) { + var coordinates = {}; + + if (this.internal) { + var mmtopx = function mmtopx(x) { + return x * this.internal.scaleFactor; + }; + + if (Array.isArray(x)) { + x[0] = AcroForm.scale(x[0]); + x[1] = AcroForm.scale(x[1]); + x[2] = AcroForm.scale(x[2]); + x[3] = AcroForm.scale(x[3]); + + coordinates.lowerLeft_X = x[0] || 0; + coordinates.lowerLeft_Y = mmtopx.call(this, this.internal.pageSize.height) - x[3] - x[1] || 0; + coordinates.upperRight_X = x[0] + x[2] || 0; + coordinates.upperRight_Y = mmtopx.call(this, this.internal.pageSize.height) - x[1] || 0; + } else { + x = AcroForm.scale(x); + y = AcroForm.scale(y); + w = AcroForm.scale(w); + h = AcroForm.scale(h); + coordinates.lowerLeft_X = x || 0; + coordinates.lowerLeft_Y = this.internal.pageSize.height - y || 0; + coordinates.upperRight_X = x + w || 0; + coordinates.upperRight_Y = this.internal.pageSize.height - y + h || 0; + } + } else { + // old method, that is fallback, if we can't get the pageheight, the coordinate-system starts from lower left + if (Array.isArray(x)) { + coordinates.lowerLeft_X = x[0] || 0; + coordinates.lowerLeft_Y = x[1] || 0; + coordinates.upperRight_X = x[0] + x[2] || 0; + coordinates.upperRight_Y = x[1] + x[3] || 0; + } else { + coordinates.lowerLeft_X = x || 0; + coordinates.lowerLeft_Y = y || 0; + coordinates.upperRight_X = x + w || 0; + coordinates.upperRight_Y = y + h || 0; + } + } + + return [coordinates.lowerLeft_X, coordinates.lowerLeft_Y, coordinates.upperRight_X, coordinates.upperRight_Y]; +}; + +AcroForm.internal.calculateColor = function (r, g, b) { + var color = new Array(3); + color.r = r | 0; + color.g = g | 0; + color.b = b | 0; + return color; +}; + +AcroForm.internal.getBitPosition = function (variable, position) { + variable = variable || 0; + var bitMask = 1; + bitMask = bitMask << position - 1; + return variable | bitMask; +}; + +AcroForm.internal.setBitPosition = function (variable, position, value) { + variable = variable || 0; + value = value || 1; + + var bitMask = 1; + bitMask = bitMask << position - 1; + + if (value == 1) { + // Set the Bit to 1 + var variable = variable | bitMask; + } else { + // Set the Bit to 0 + var variable = variable & ~bitMask; + } + + return variable; +}; + +/** + * jsPDF addHTML PlugIn + * Copyright (c) 2014 Diego Casorran + * + * Licensed under the MIT License. + * http://opensource.org/licenses/mit-license + */ + +(function (jsPDFAPI) { + 'use strict'; + + /** + * Renders an HTML element to canvas object which added to the PDF + * + * This PlugIn requires html2canvas: https://github.com/niklasvh/html2canvas + * OR rasterizeHTML: https://github.com/cburgmer/rasterizeHTML.js + * + * @public + * @function + * @param element {Mixed} HTML Element, or anything supported by html2canvas. + * @param x {Number} starting X coordinate in jsPDF instance's declared units. + * @param y {Number} starting Y coordinate in jsPDF instance's declared units. + * @param options {Object} Additional options, check the code below. + * @param callback {Function} to call when the rendering has finished. + * + * NOTE: Every parameter is optional except 'element' and 'callback', in such + * case the image is positioned at 0x0 covering the whole PDF document + * size. Ie, to easily take screenshots of webpages saving them to PDF. + */ + + jsPDFAPI.addHTML = function (element, x, y, options, callback) { + 'use strict'; + + if (typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined') throw new Error('You need either ' + 'https://github.com/niklasvh/html2canvas' + ' or https://github.com/cburgmer/rasterizeHTML.js'); + + if (typeof x !== 'number') { + options = x; + callback = y; + } + + if (typeof options === 'function') { + callback = options; + options = null; + } + + var I = this.internal, + K = I.scaleFactor, + W = I.pageSize.width, + H = I.pageSize.height; + + options = options || {}; + options.onrendered = function (obj) { + x = parseInt(x) || 0; + y = parseInt(y) || 0; + var dim = options.dim || {}; + var h = dim.h || 0; + var w = dim.w || Math.min(W, obj.width / K) - x; + + var format = 'JPEG'; + if (options.format) format = options.format; + + if (obj.height > H && options.pagesplit) { + var crop = function () { + var cy = 0; + while (1) { + var canvas = document.createElement('canvas'); + canvas.width = Math.min(W * K, obj.width); + canvas.height = Math.min(H * K, obj.height - cy); + var ctx = canvas.getContext('2d'); + ctx.drawImage(obj, 0, cy, obj.width, canvas.height, 0, 0, canvas.width, canvas.height); + var args = [canvas, x, cy ? 0 : y, canvas.width / K, canvas.height / K, format, null, 'SLOW']; + this.addImage.apply(this, args); + cy += canvas.height; + if (cy >= obj.height) break; + this.addPage(); + } + callback(w, cy, null, args); + }.bind(this); + if (obj.nodeName === 'CANVAS') { + var img = new Image(); + img.onload = crop; + img.src = obj.toDataURL("image/png"); + obj = img; + } else { + crop(); + } + } else { + var alias = Math.random().toString(35); + var args = [obj, x, y, w, h, format, alias, 'SLOW']; + + this.addImage.apply(this, args); + + callback(w, h, alias, args); + } + }.bind(this); + + if (typeof html2canvas !== 'undefined' && !options.rstz) { + return html2canvas(element, options); + } + + if (typeof rasterizeHTML !== 'undefined') { + var meth = 'drawDocument'; + if (typeof element === 'string') { + meth = /^http/.test(element) ? 'drawURL' : 'drawHTML'; + } + options.width = options.width || W * K; + return rasterizeHTML[meth](element, void 0, options).then(function (r) { + options.onrendered(r.image); + }, function (e) { + callback(null, e); + }); + } + + return null; + }; +})(jsPDF.API); + +/** @preserve + * jsPDF addImage plugin + * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/ + * 2013 Chris Dowling, https://github.com/gingerchris + * 2013 Trinh Ho, https://github.com/ineedfat + * 2013 Edwin Alejandro Perez, https://github.com/eaparango + * 2013 Norah Smith, https://github.com/burnburnrocket + * 2014 Diego Casorran, https://github.com/diegocr + * 2014 James Robb, https://github.com/jamesbrobb + * + * + */ + +(function (jsPDFAPI) { + 'use strict'; + + var namespace = 'addImage_', + supported_image_types = ['jpeg', 'jpg', 'png']; + + // Image functionality ported from pdf.js + var putImage = function putImage(img) { + + var objectNumber = this.internal.newObject(), + out = this.internal.write, + putStream = this.internal.putStream; + + img['n'] = objectNumber; + + out('<>'); + } + if ('trns' in img && img['trns'].constructor == Array) { + var trns = '', + i = 0, + len = img['trns'].length; + for (; i < len; i++) { + trns += img['trns'][i] + ' ' + img['trns'][i] + ' '; + }out('/Mask [' + trns + ']'); + } + if ('smask' in img) { + out('/SMask ' + (objectNumber + 1) + ' 0 R'); + } + out('/Length ' + img['data'].length + '>>'); + + putStream(img['data']); + + out('endobj'); + + // Soft mask + if ('smask' in img) { + var dp = '/Predictor ' + img['p'] + ' /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w']; + var smask = { 'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask'] }; + if ('f' in img) smask.f = img['f']; + putImage.call(this, smask); + } + + //Palette + if (img['cs'] === this.color_spaces.INDEXED) { + + this.internal.newObject(); + //out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>'); + //putStream(zlib.compress(img['pal'])); + out('<< /Length ' + img['pal'].length + '>>'); + putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal']))); + out('endobj'); + } + }, + putResourcesCallback = function putResourcesCallback() { + var images = this.internal.collections[namespace + 'images']; + for (var i in images) { + putImage.call(this, images[i]); + } + }, + putXObjectsDictCallback = function putXObjectsDictCallback() { + var images = this.internal.collections[namespace + 'images'], + out = this.internal.write, + image; + for (var i in images) { + image = images[i]; + out('/I' + image['i'], image['n'], '0', 'R'); + } + }, + checkCompressValue = function checkCompressValue(value) { + if (value && typeof value === 'string') value = value.toUpperCase(); + return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE; + }, + getImages = function getImages() { + var images = this.internal.collections[namespace + 'images']; + //first run, so initialise stuff + if (!images) { + this.internal.collections[namespace + 'images'] = images = {}; + this.internal.events.subscribe('putResources', putResourcesCallback); + this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback); + } + + return images; + }, + getImageIndex = function getImageIndex(images) { + var imageIndex = 0; + + if (images) { + // this is NOT the first time this method is ran on this instance of jsPDF object. + imageIndex = Object.keys ? Object.keys(images).length : function (o) { + var i = 0; + for (var e in o) { + if (o.hasOwnProperty(e)) { + i++; + } + } + return i; + }(images); + } + + return imageIndex; + }, + notDefined = function notDefined(value) { + return typeof value === 'undefined' || value === null; + }, + generateAliasFromData = function generateAliasFromData(data) { + return typeof data === 'string' && jsPDFAPI.sHashCode(data); + }, + doesNotSupportImageType = function doesNotSupportImageType(type) { + return supported_image_types.indexOf(type) === -1; + }, + processMethodNotEnabled = function processMethodNotEnabled(type) { + return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function'; + }, + isDOMElement = function isDOMElement(object) { + return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object.nodeType === 1; + }, + createDataURIFromElement = function createDataURIFromElement(element, format, angle) { + + //if element is an image which uses data url definition, just return the dataurl + if (element.nodeName === 'IMG' && element.hasAttribute('src')) { + var src = '' + element.getAttribute('src'); + if (!angle && src.indexOf('data:image/') === 0) return src; + + // only if the user doesn't care about a format + if (!format && /\.png(?:[?#].*)?$/i.test(src)) format = 'png'; + } + + if (element.nodeName === 'CANVAS') { + var canvas = element; + } else { + var canvas = document.createElement('canvas'); + canvas.width = element.clientWidth || element.width; + canvas.height = element.clientHeight || element.height; + + var ctx = canvas.getContext('2d'); + if (!ctx) { + throw 'addImage requires canvas to be supported by browser.'; + } + if (angle) { + var x, + y, + b, + c, + s, + w, + h, + to_radians = Math.PI / 180, + angleInRadians; + + if ((typeof angle === 'undefined' ? 'undefined' : _typeof(angle)) === 'object') { + x = angle.x; + y = angle.y; + b = angle.bg; + angle = angle.angle; + } + angleInRadians = angle * to_radians; + c = Math.abs(Math.cos(angleInRadians)); + s = Math.abs(Math.sin(angleInRadians)); + w = canvas.width; + h = canvas.height; + canvas.width = h * s + w * c; + canvas.height = h * c + w * s; + + if (isNaN(x)) x = canvas.width / 2; + if (isNaN(y)) y = canvas.height / 2; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = b || 'white'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.save(); + ctx.translate(x, y); + ctx.rotate(angleInRadians); + ctx.drawImage(element, -(w / 2), -(h / 2)); + ctx.rotate(-angleInRadians); + ctx.translate(-x, -y); + ctx.restore(); + } else { + ctx.drawImage(element, 0, 0, canvas.width, canvas.height); + } + } + return canvas.toDataURL(('' + format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg'); + }, + checkImagesForAlias = function checkImagesForAlias(alias, images) { + var cached_info; + if (images) { + for (var e in images) { + if (alias === images[e].alias) { + cached_info = images[e]; + break; + } + } + } + return cached_info; + }, + determineWidthAndHeight = function determineWidthAndHeight(w, h, info) { + if (!w && !h) { + w = -96; + h = -96; + } + if (w < 0) { + w = -1 * info['w'] * 72 / w / this.internal.scaleFactor; + } + if (h < 0) { + h = -1 * info['h'] * 72 / h / this.internal.scaleFactor; + } + if (w === 0) { + w = h * info['w'] / info['h']; + } + if (h === 0) { + h = w * info['h'] / info['w']; + } + + return [w, h]; + }, + writeImageToPDF = function writeImageToPDF(x, y, w, h, info, index, images) { + var dims = determineWidthAndHeight.call(this, w, h, info), + coord = this.internal.getCoordinateString, + vcoord = this.internal.getVerticalCoordinateString; + + w = dims[0]; + h = dims[1]; + + images[index] = info; + + this.internal.write('q', coord(w), '0 0', coord(h) // TODO: check if this should be shifted by vcoord + , coord(x), vcoord(y + h), 'cm /I' + info['i'], 'Do Q'); + }; + + /** + * COLOR SPACES + */ + jsPDFAPI.color_spaces = { + DEVICE_RGB: 'DeviceRGB', + DEVICE_GRAY: 'DeviceGray', + DEVICE_CMYK: 'DeviceCMYK', + CAL_GREY: 'CalGray', + CAL_RGB: 'CalRGB', + LAB: 'Lab', + ICC_BASED: 'ICCBased', + INDEXED: 'Indexed', + PATTERN: 'Pattern', + SEPARATION: 'Separation', + DEVICE_N: 'DeviceN' + }; + + /** + * DECODE METHODS + */ + jsPDFAPI.decode = { + DCT_DECODE: 'DCTDecode', + FLATE_DECODE: 'FlateDecode', + LZW_DECODE: 'LZWDecode', + JPX_DECODE: 'JPXDecode', + JBIG2_DECODE: 'JBIG2Decode', + ASCII85_DECODE: 'ASCII85Decode', + ASCII_HEX_DECODE: 'ASCIIHexDecode', + RUN_LENGTH_DECODE: 'RunLengthDecode', + CCITT_FAX_DECODE: 'CCITTFaxDecode' + }; + + /** + * IMAGE COMPRESSION TYPES + */ + jsPDFAPI.image_compression = { + NONE: 'NONE', + FAST: 'FAST', + MEDIUM: 'MEDIUM', + SLOW: 'SLOW' + }; + + jsPDFAPI.sHashCode = function (str) { + return Array.prototype.reduce && str.split("").reduce(function (a, b) { + a = (a << 5) - a + b.charCodeAt(0);return a & a; + }, 0); + }; + + jsPDFAPI.isString = function (object) { + return typeof object === 'string'; + }; + + /** + * Strips out and returns info from a valid base64 data URI + * @param {String[dataURI]} a valid data URI of format 'data:[][;base64],' + * @returns an Array containing the following + * [0] the complete data URI + * [1] + * [2] format - the second part of the mime-type i.e 'png' in 'image/png' + * [4] + */ + jsPDFAPI.extractInfoFromBase64DataURI = function (dataURI) { + return (/^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI) + ); + }; + + /** + * Check to see if ArrayBuffer is supported + */ + jsPDFAPI.supportsArrayBuffer = function () { + return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined'; + }; + + /** + * Tests supplied object to determine if ArrayBuffer + * @param {Object[object]} + */ + jsPDFAPI.isArrayBuffer = function (object) { + if (!this.supportsArrayBuffer()) return false; + return object instanceof ArrayBuffer; + }; + + /** + * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface + * @param {Object[object]} + */ + jsPDFAPI.isArrayBufferView = function (object) { + if (!this.supportsArrayBuffer()) return false; + if (typeof Uint32Array === 'undefined') return false; + return object instanceof Int8Array || object instanceof Uint8Array || typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray || object instanceof Int16Array || object instanceof Uint16Array || object instanceof Int32Array || object instanceof Uint32Array || object instanceof Float32Array || object instanceof Float64Array; + }; + + /** + * Exactly what it says on the tin + */ + jsPDFAPI.binaryStringToUint8Array = function (binary_string) { + /* + * not sure how efficient this will be will bigger files. Is there a native method? + */ + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; + }; + + /** + * @see this discussion + * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers + * + * As stated, i imagine the method below is highly inefficent for large files. + * + * Also of note from Mozilla, + * + * "However, this is slow and error-prone, due to the need for multiple conversions (especially if the binary data is not actually byte-format data, but, for example, 32-bit integers or floats)." + * + * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView + * + * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion? + * + * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow? + */ + jsPDFAPI.arrayBufferToBinaryString = function (buffer) { + /*if('TextDecoder' in window){ + var decoder = new TextDecoder('ascii'); + return decoder.decode(buffer); + }*/ + + if (this.isArrayBuffer(buffer)) buffer = new Uint8Array(buffer); + + var binary_string = ''; + var len = buffer.byteLength; + for (var i = 0; i < len; i++) { + binary_string += String.fromCharCode(buffer[i]); + } + return binary_string; + /* + * Another solution is the method below - convert array buffer straight to base64 and then use atob + */ + //return atob(this.arrayBufferToBase64(buffer)); + }; + + /** + * Converts an ArrayBuffer directly to base64 + * + * Taken from here + * + * http://jsperf.com/encoding-xhr-image-data/31 + * + * Need to test if this is a better solution for larger files + * + */ + jsPDFAPI.arrayBufferToBase64 = function (arrayBuffer) { + var base64 = ''; + var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + + var bytes = new Uint8Array(arrayBuffer); + var byteLength = bytes.byteLength; + var byteRemainder = byteLength % 3; + var mainLength = byteLength - byteRemainder; + + var a, b, c, d; + var chunk; + + // Main loop deals with bytes in chunks of 3 + for (var i = 0; i < mainLength; i = i + 3) { + // Combine the three bytes into a single integer + chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; + + // Use bitmasks to extract 6-bit segments from the triplet + a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 + b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 + c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 + d = chunk & 63; // 63 = 2^6 - 1 + + // Convert the raw binary segments to the appropriate ASCII encoding + base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; + } + + // Deal with the remaining bytes and padding + if (byteRemainder == 1) { + chunk = bytes[mainLength]; + + a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 + + // Set the 4 least significant bits to zero + b = (chunk & 3) << 4; // 3 = 2^2 - 1 + + base64 += encodings[a] + encodings[b] + '=='; + } else if (byteRemainder == 2) { + chunk = bytes[mainLength] << 8 | bytes[mainLength + 1]; + + a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 + b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 + + // Set the 2 least significant bits to zero + c = (chunk & 15) << 2; // 15 = 2^4 - 1 + + base64 += encodings[a] + encodings[b] + encodings[c] + '='; + } + + return base64; + }; + + jsPDFAPI.createImageInfo = function (data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask, p) { + var info = { + alias: alias, + w: wd, + h: ht, + cs: cs, + bpc: bpc, + i: imageIndex, + data: data + // n: objectNumber will be added by putImage code + }; + + if (f) info.f = f; + if (dp) info.dp = dp; + if (trns) info.trns = trns; + if (pal) info.pal = pal; + if (smask) info.smask = smask; + if (p) info.p = p; // predictor parameter for PNG compression + + return info; + }; + + jsPDFAPI.addImage = function (imageData, format, x, y, w, h, alias, compression, rotation) { + 'use strict'; + + if (typeof format !== 'string') { + var tmp = h; + h = w; + w = y; + y = x; + x = format; + format = tmp; + } + + if ((typeof imageData === 'undefined' ? 'undefined' : _typeof(imageData)) === 'object' && !isDOMElement(imageData) && "imageData" in imageData) { + var options = imageData; + + imageData = options.imageData; + format = options.format || format; + x = options.x || x || 0; + y = options.y || y || 0; + w = options.w || w; + h = options.h || h; + alias = options.alias || alias; + compression = options.compression || compression; + rotation = options.rotation || options.angle || rotation; + } + + if (isNaN(x) || isNaN(y)) { + console.error('jsPDF.addImage: Invalid coordinates', arguments); + throw new Error('Invalid coordinates passed to jsPDF.addImage'); + } + + var images = getImages.call(this), + info; + + if (!(info = checkImagesForAlias(imageData, images))) { + var dataAsBinaryString; + + if (isDOMElement(imageData)) imageData = createDataURIFromElement(imageData, format, rotation); + + if (notDefined(alias)) alias = generateAliasFromData(imageData); + + if (!(info = checkImagesForAlias(alias, images))) { + + if (this.isString(imageData)) { + + var base64Info = this.extractInfoFromBase64DataURI(imageData); + + if (base64Info) { + + format = base64Info[2]; + imageData = atob(base64Info[3]); //convert to binary string + } else { + + if (imageData.charCodeAt(0) === 0x89 && imageData.charCodeAt(1) === 0x50 && imageData.charCodeAt(2) === 0x4e && imageData.charCodeAt(3) === 0x47) format = 'png'; + } + } + format = (format || 'JPEG').toLowerCase(); + + if (doesNotSupportImageType(format)) throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \'' + format + '\''); + + if (processMethodNotEnabled(format)) throw new Error('please ensure that the plugin for \'' + format + '\' support is added'); + + /** + * need to test if it's more efficient to convert all binary strings + * to TypedArray - or should we just leave and process as string? + */ + if (this.supportsArrayBuffer()) { + // no need to convert if imageData is already uint8array + if (!(imageData instanceof Uint8Array)) { + dataAsBinaryString = imageData; + imageData = this.binaryStringToUint8Array(imageData); + } + } + + info = this['process' + format.toUpperCase()](imageData, getImageIndex(images), alias, checkCompressValue(compression), dataAsBinaryString); + + if (!info) throw new Error('An unkwown error occurred whilst processing the image'); + } + } + + writeImageToPDF.call(this, x, y, w, h, info, info.i, images); + + return this; + }; + + /** + * JPEG SUPPORT + **/ + + //takes a string imgData containing the raw bytes of + //a jpeg image and returns [width, height] + //Algorithm from: http://www.64lines.com/jpeg-width-height + var getJpegSize = function getJpegSize(imgData) { + 'use strict'; + + var width, height, numcomponents; + // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00 + if (!imgData.charCodeAt(0) === 0xff || !imgData.charCodeAt(1) === 0xd8 || !imgData.charCodeAt(2) === 0xff || !imgData.charCodeAt(3) === 0xe0 || !imgData.charCodeAt(6) === 'J'.charCodeAt(0) || !imgData.charCodeAt(7) === 'F'.charCodeAt(0) || !imgData.charCodeAt(8) === 'I'.charCodeAt(0) || !imgData.charCodeAt(9) === 'F'.charCodeAt(0) || !imgData.charCodeAt(10) === 0x00) { + throw new Error('getJpegSize requires a binary string jpeg file'); + } + var blockLength = imgData.charCodeAt(4) * 256 + imgData.charCodeAt(5); + var i = 4, + len = imgData.length; + while (i < len) { + i += blockLength; + if (imgData.charCodeAt(i) !== 0xff) { + throw new Error('getJpegSize could not find the size of the image'); + } + if (imgData.charCodeAt(i + 1) === 0xc0 || //(SOF) Huffman - Baseline DCT + imgData.charCodeAt(i + 1) === 0xc1 || //(SOF) Huffman - Extended sequential DCT + imgData.charCodeAt(i + 1) === 0xc2 || // Progressive DCT (SOF2) + imgData.charCodeAt(i + 1) === 0xc3 || // Spatial (sequential) lossless (SOF3) + imgData.charCodeAt(i + 1) === 0xc4 || // Differential sequential DCT (SOF5) + imgData.charCodeAt(i + 1) === 0xc5 || // Differential progressive DCT (SOF6) + imgData.charCodeAt(i + 1) === 0xc6 || // Differential spatial (SOF7) + imgData.charCodeAt(i + 1) === 0xc7) { + height = imgData.charCodeAt(i + 5) * 256 + imgData.charCodeAt(i + 6); + width = imgData.charCodeAt(i + 7) * 256 + imgData.charCodeAt(i + 8); + numcomponents = imgData.charCodeAt(i + 9); + return [width, height, numcomponents]; + } else { + i += 2; + blockLength = imgData.charCodeAt(i) * 256 + imgData.charCodeAt(i + 1); + } + } + }, + getJpegSizeFromBytes = function getJpegSizeFromBytes(data) { + + var hdr = data[0] << 8 | data[1]; + + if (hdr !== 0xFFD8) throw new Error('Supplied data is not a JPEG'); + + var len = data.length, + block = (data[4] << 8) + data[5], + pos = 4, + bytes, + width, + height, + numcomponents; + + while (pos < len) { + pos += block; + bytes = readBytes(data, pos); + block = (bytes[2] << 8) + bytes[3]; + if ((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) { + bytes = readBytes(data, pos + 5); + width = (bytes[2] << 8) + bytes[3]; + height = (bytes[0] << 8) + bytes[1]; + numcomponents = bytes[4]; + return { width: width, height: height, numcomponents: numcomponents }; + } + + pos += 2; + } + + throw new Error('getJpegSizeFromBytes could not find the size of the image'); + }, + readBytes = function readBytes(data, offset) { + return data.subarray(offset, offset + 5); + }; + + jsPDFAPI.processJPEG = function (data, index, alias, compression, dataAsBinaryString) { + 'use strict'; + + var colorSpace = this.color_spaces.DEVICE_RGB, + filter = this.decode.DCT_DECODE, + bpc = 8, + dims; + + if (this.isString(data)) { + dims = getJpegSize(data); + return this.createImageInfo(data, dims[0], dims[1], dims[3] == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias); + } + + if (this.isArrayBuffer(data)) data = new Uint8Array(data); + + if (this.isArrayBufferView(data)) { + + dims = getJpegSizeFromBytes(data); + + // if we already have a stored binary string rep use that + data = dataAsBinaryString || this.arrayBufferToBinaryString(data); + + return this.createImageInfo(data, dims.width, dims.height, dims.numcomponents == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias); + } + + return null; + }; + + jsPDFAPI.processJPG = function () /*data, index, alias, compression, dataAsBinaryString*/{ + return this.processJPEG.apply(this, arguments); + }; +})(jsPDF.API); + +/** + * jsPDF Annotations PlugIn + * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv + * + * Licensed under the MIT License. + * http://opensource.org/licenses/mit-license + */ + +/** + * There are many types of annotations in a PDF document. Annotations are placed + * on a page at a particular location. They are not 'attached' to an object. + *
+ * This plugin current supports
+ *
  • Goto Page (set pageNumber and top in options) + *
  • Goto Name (set name and top in options) + *
  • Goto URL (set url in options) + *

    + * The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below) + * (set magFactor in options). XYZ is the default. + *

    + *

    + * Links, Text, Popup, and FreeText are supported. + *

    + *

    + * Options In PDF spec Not Implemented Yet + *

  • link border + *
  • named target + *
  • page coordinates + *
  • destination page scaling and layout + *
  • actions other than URL and GotoPage + *
  • background / hover actions + *

    + */ + +/* + Destination Magnification Factors + See PDF 1.3 Page 386 for meanings and options + + [supported] + XYZ (options; left top zoom) + Fit (no options) + FitH (options: top) + FitV (options: left) + + [not supported] + FitR + FitB + FitBH + FitBV + */ + +(function (jsPDFAPI) { + 'use strict'; + + var annotationPlugin = { + + /** + * An array of arrays, indexed by pageNumber. + */ + annotations: [], + + f2: function f2(number) { + return number.toFixed(2); + }, + + notEmpty: function notEmpty(obj) { + if (typeof obj != 'undefined') { + if (obj != '') { + return true; + } + } + } + }; + + jsPDF.API.annotationPlugin = annotationPlugin; + + jsPDF.API.events.push(['addPage', function (info) { + this.annotationPlugin.annotations[info.pageNumber] = []; + }]); + + jsPDFAPI.events.push(['putPage', function (info) { + //TODO store annotations in pageContext so reorder/remove will not affect them. + var pageAnnos = this.annotationPlugin.annotations[info.pageNumber]; + + var found = false; + for (var a = 0; a < pageAnnos.length && !found; a++) { + var anno = pageAnnos[a]; + switch (anno.type) { + case 'link': + if (annotationPlugin.notEmpty(anno.options.url) || annotationPlugin.notEmpty(anno.options.pageNumber)) { + found = true; + break; + } + case 'reference': + case 'text': + case 'freetext': + found = true; + break; + } + } + if (found == false) { + return; + } + + this.internal.write("/Annots ["); + var f2 = this.annotationPlugin.f2; + var k = this.internal.scaleFactor; + var pageHeight = this.internal.pageSize.height; + var pageInfo = this.internal.getPageInfo(info.pageNumber); + for (var a = 0; a < pageAnnos.length; a++) { + var anno = pageAnnos[a]; + + switch (anno.type) { + case 'reference': + // References to Widget Anotations (for AcroForm Fields) + this.internal.write(' ' + anno.object.objId + ' 0 R '); + break; + case 'text': + // Create a an object for both the text and the popup + var objText = this.internal.newAdditionalObject(); + var objPopup = this.internal.newAdditionalObject(); + + var title = anno.title || 'Note'; + var rect = "/Rect [" + f2(anno.bounds.x * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + " " + f2((anno.bounds.x + anno.bounds.w) * k) + " " + f2((pageHeight - anno.bounds.y) * k) + "] "; + line = '<>'; + objText.content = line; + + var parent = objText.objId + ' 0 R'; + var popoff = 30; + var rect = "/Rect [" + f2((anno.bounds.x + popoff) * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + " " + f2((anno.bounds.x + anno.bounds.w + popoff) * k) + " " + f2((pageHeight - anno.bounds.y) * k) + "] "; + //var rect2 = "/Rect [" + f2(anno.bounds.x * k) + " " + f2((pageHeight - anno.bounds.y) * k) + " " + f2(anno.bounds.x + anno.bounds.w * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + "] "; + line = '<>'; + } else if (anno.options.pageNumber) { + // first page is 0 + var info = this.internal.getPageInfo(anno.options.pageNumber); + line = '< pageNumber or url [required] + *

    If pageNumber is specified, top and zoom may also be specified

    + */ + jsPDFAPI.link = function (x, y, w, h, options) { + 'use strict'; + + this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({ + x: x, + y: y, + w: w, + h: h, + options: options, + type: 'link' + }); + }; + + /** + * valid options + *
  • pageNumber or url [required] + *

    If pageNumber is specified, top and zoom may also be specified

    + */ + jsPDFAPI.link = function (x, y, w, h, options) { + 'use strict'; + + this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({ + x: x, + y: y, + w: w, + h: h, + options: options, + type: 'link' + }); + }; + + /** + * Currently only supports single line text. + * Returns the width of the text/link + */ + jsPDFAPI.textWithLink = function (text, x, y, options) { + 'use strict'; + + var width = this.getTextWidth(text); + var height = this.internal.getLineHeight(); + this.text(text, x, y); + //TODO We really need the text baseline height to do this correctly. + // Or ability to draw text on top, bottom, center, or baseline. + y += height * .2; + this.link(x, y - height, width, height, options); + return width; + }; + + //TODO move into external library + jsPDFAPI.getTextWidth = function (text) { + 'use strict'; + + var fontSize = this.internal.getFontSize(); + var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor; + return txtWidth; + }; + + //TODO move into external library + jsPDFAPI.getLineHeight = function () { + return this.internal.getLineHeight(); + }; + + return this; +})(jsPDF.API); + +/** + * jsPDF Autoprint Plugin + * + * Licensed under the MIT License. + * http://opensource.org/licenses/mit-license + */ + +(function (jsPDFAPI) { + 'use strict'; + + jsPDFAPI.autoPrint = function () { + 'use strict'; + + var refAutoPrintTag; + + this.internal.events.subscribe('postPutResources', function () { + refAutoPrintTag = this.internal.newObject(); + this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj"); + }); + + this.internal.events.subscribe("putCatalog", function () { + this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R"); + }); + return this; + }; +})(jsPDF.API); + +/** + * jsPDF Canvas PlugIn + * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv + * + * Licensed under the MIT License. + * http://opensource.org/licenses/mit-license + */ + +/** + * This plugin mimics the HTML5 Canvas + * + * The goal is to provide a way for current canvas users to print directly to a PDF. + */ + +(function (jsPDFAPI) { + 'use strict'; + + jsPDFAPI.events.push(['initialized', function () { + this.canvas.pdf = this; + }]); + + jsPDFAPI.canvas = { + getContext: function getContext(name) { + this.pdf.context2d._canvas = this; + return this.pdf.context2d; + }, + style: {} + }; + + Object.defineProperty(jsPDFAPI.canvas, 'width', { + get: function get() { + return this._width; + }, + set: function set(value) { + this._width = value; + this.getContext('2d').pageWrapX = value + 1; + } + }); + + Object.defineProperty(jsPDFAPI.canvas, 'height', { + get: function get() { + return this._height; + }, + set: function set(value) { + this._height = value; + this.getContext('2d').pageWrapY = value + 1; + } + }); + + return this; +})(jsPDF.API); + +/** ==================================================================== + * jsPDF Cell plugin + * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com + * 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br + * 2013 Lee Driscoll, https://github.com/lsdriscoll + * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria + * 2014 James Hall, james@parall.ax + * 2014 Diego Casorran, https://github.com/diegocr + * + * + * ==================================================================== + */ + +(function (jsPDFAPI) { + 'use strict'; + /*jslint browser:true */ + /*global document: false, jsPDF */ + + var fontName, + fontSize, + fontStyle, + padding = 3, + margin = 13, + headerFunction, + lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, + pages = 1, + setLastCellPosition = function setLastCellPosition(x, y, w, h, ln) { + lastCellPos = { 'x': x, 'y': y, 'w': w, 'h': h, 'ln': ln }; + }, + getLastCellPosition = function getLastCellPosition() { + return lastCellPos; + }, + NO_MARGINS = { left: 0, top: 0, bottom: 0 }; + + jsPDFAPI.setHeaderFunction = function (func) { + headerFunction = func; + }; + + jsPDFAPI.getTextDimensions = function (txt) { + fontName = this.internal.getFont().fontName; + fontSize = this.table_font_size || this.internal.getFontSize(); + fontStyle = this.internal.getFont().fontStyle; + // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point + var px2pt = 0.264583 * 72 / 25.4, + dimensions, + text; + + text = document.createElement('font'); + text.id = "jsPDFCell"; + + try { + text.style.fontStyle = fontStyle; + } catch (e) { + text.style.fontWeight = fontStyle; + } + + text.style.fontName = fontName; + text.style.fontSize = fontSize + 'pt'; + try { + text.textContent = txt; + } catch (e) { + text.innerText = txt; + } + + document.body.appendChild(text); + + dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt }; + + document.body.removeChild(text); + + return dimensions; + }; + + jsPDFAPI.cellAddPage = function () { + var margins = this.margins || NO_MARGINS; + + this.addPage(); + + setLastCellPosition(margins.left, margins.top, undefined, undefined); + //setLastCellPosition(undefined, undefined, undefined, undefined, undefined); + pages += 1; + }; + + jsPDFAPI.cellInitialize = function () { + lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }; + pages = 1; + }; + + jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) { + var curCell = getLastCellPosition(); + var pgAdded = false; + + // If this is not the first cell, we must change its position + if (curCell.ln !== undefined) { + if (curCell.ln === ln) { + //Same line + x = curCell.x + curCell.w; + y = curCell.y; + } else { + //New line + var margins = this.margins || NO_MARGINS; + if (curCell.y + curCell.h + h + margin >= this.internal.pageSize.height - margins.bottom) { + this.cellAddPage(); + pgAdded = true; + if (this.printHeaders && this.tableHeaderRow) { + this.printHeaderRow(ln, true); + } + } + //We ignore the passed y: the lines may have different heights + y = getLastCellPosition().y + getLastCellPosition().h; + if (pgAdded) y = margin + 10; + } + } + + if (txt[0] !== undefined) { + if (this.printingHeaderRow) { + this.rect(x, y, w, h, 'FD'); + } else { + this.rect(x, y, w, h); + } + if (align === 'right') { + if (!(txt instanceof Array)) { + txt = [txt]; + } + for (var i = 0; i < txt.length; i++) { + var currentLine = txt[i]; + var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize(); + this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight() * (i + 1)); + } + } else { + this.text(txt, x + padding, y + this.internal.getLineHeight()); + } + } + setLastCellPosition(x, y, w, h, ln); + return this; + }; + + /** + * Return the maximum value from an array + * @param array + * @param comparisonFn + * @returns {*} + */ + jsPDFAPI.arrayMax = function (array, comparisonFn) { + var max = array[0], + i, + ln, + item; + + for (i = 0, ln = array.length; i < ln; i += 1) { + item = array[i]; + + if (comparisonFn) { + if (comparisonFn(max, item) === -1) { + max = item; + } + } else { + if (item > max) { + max = item; + } + } + } + + return max; + }; + + /** + * Create a table from a set of data. + * @param {Integer} [x] : left-position for top-left corner of table + * @param {Integer} [y] top-position for top-left corner of table + * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data. + * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost + * @param {Object} [config.printHeaders] True to print column headers at the top of every page + * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value + * @param {Object} [config.margins] margin values for left, top, bottom, and width + * @param {Object} [config.fontSize] Integer fontSize to use (optional) + */ + + jsPDFAPI.table = function (x, y, data, headers, config) { + if (!data) { + throw 'No data for PDF table'; + } + + var headerNames = [], + headerPrompts = [], + header, + i, + ln, + cln, + columnMatrix = {}, + columnWidths = {}, + columnData, + column, + columnMinWidths = [], + j, + tableHeaderConfigs = [], + model, + jln, + func, + + + //set up defaults. If a value is provided in config, defaults will be overwritten: + autoSize = false, + printHeaders = true, + fontSize = 12, + margins = NO_MARGINS; + + margins.width = this.internal.pageSize.width; + + if (config) { + //override config defaults if the user has specified non-default behavior: + if (config.autoSize === true) { + autoSize = true; + } + if (config.printHeaders === false) { + printHeaders = false; + } + if (config.fontSize) { + fontSize = config.fontSize; + } + if (config.css && typeof config.css['font-size'] !== "undefined") { + fontSize = config.css['font-size'] * 16; + } + if (config.margins) { + margins = config.margins; + } + } + + /** + * @property {Number} lnMod + * Keep track of the current line number modifier used when creating cells + */ + this.lnMod = 0; + lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, pages = 1; + + this.printHeaders = printHeaders; + this.margins = margins; + this.setFontSize(fontSize); + this.table_font_size = fontSize; + + // Set header values + if (headers === undefined || headers === null) { + // No headers defined so we derive from data + headerNames = Object.keys(data[0]); + } else if (headers[0] && typeof headers[0] !== 'string') { + var px2pt = 0.264583 * 72 / 25.4; + + // Split header configs into names and prompts + for (i = 0, ln = headers.length; i < ln; i += 1) { + header = headers[i]; + headerNames.push(header.name); + headerPrompts.push(header.prompt); + columnWidths[header.name] = header.width * px2pt; + } + } else { + headerNames = headers; + } + + if (autoSize) { + // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]} + func = function func(rec) { + return rec[header]; + }; + + for (i = 0, ln = headerNames.length; i < ln; i += 1) { + header = headerNames[i]; + + columnMatrix[header] = data.map(func); + + // get header width + columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w); + column = columnMatrix[header]; + + // get cell widths + for (j = 0, cln = column.length; j < cln; j += 1) { + columnData = column[j]; + columnMinWidths.push(this.getTextDimensions(columnData).w); + } + + // get final column width + columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths); + + //have to reset + columnMinWidths = []; + } + } + + // -- Construct the table + + if (printHeaders) { + var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length ? headerPrompts : headerNames); + + // Construct the header row + for (i = 0, ln = headerNames.length; i < ln; i += 1) { + header = headerNames[i]; + tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]); + } + + // Store the table header config + this.setTableHeaderRow(tableHeaderConfigs); + + // Print the header for the start of the table + this.printHeaderRow(1, false); + } + + // Construct the data rows + for (i = 0, ln = data.length; i < ln; i += 1) { + var lineHeight; + model = data[i]; + lineHeight = this.calculateLineHeight(headerNames, columnWidths, model); + + for (j = 0, jln = headerNames.length; j < jln; j += 1) { + header = headerNames[j]; + this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align); + } + } + this.lastCellPos = lastCellPos; + this.table_x = x; + this.table_y = y; + return this; + }; + /** + * Calculate the height for containing the highest column + * @param {String[]} headerNames is the header, used as keys to the data + * @param {Integer[]} columnWidths is size of each column + * @param {Object[]} model is the line of data we want to calculate the height of + */ + jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) { + var header, + lineHeight = 0; + for (var j = 0; j < headerNames.length; j++) { + header = headerNames[j]; + model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding); + var h = this.internal.getLineHeight() * model[header].length + padding; + if (h > lineHeight) lineHeight = h; + } + return lineHeight; + }; + + /** + * Store the config for outputting a table header + * @param {Object[]} config + * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell + * except the ln parameter is excluded + */ + jsPDFAPI.setTableHeaderRow = function (config) { + this.tableHeaderRow = config; + }; + + /** + * Output the store header row + * @param lineNumber The line number to output the header at + */ + jsPDFAPI.printHeaderRow = function (lineNumber, new_page) { + if (!this.tableHeaderRow) { + throw 'Property tableHeaderRow does not exist.'; + } + + var tableHeaderCell, tmpArray, i, ln; + + this.printingHeaderRow = true; + if (headerFunction !== undefined) { + var position = headerFunction(this, pages); + setLastCellPosition(position[0], position[1], position[2], position[3], -1); + } + this.setFontStyle('bold'); + var tempHeaderConf = []; + for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) { + this.setFillColor(200, 200, 200); + + tableHeaderCell = this.tableHeaderRow[i]; + if (new_page) { + this.margins.top = margin; + tableHeaderCell[1] = this.margins && this.margins.top || 0; + tempHeaderConf.push(tableHeaderCell); + } + tmpArray = [].concat(tableHeaderCell); + this.cell.apply(this, tmpArray.concat(lineNumber)); + } + if (tempHeaderConf.length > 0) { + this.setTableHeaderRow(tempHeaderConf); + } + this.setFontStyle('normal'); + this.printingHeaderRow = false; + }; +})(jsPDF.API); + +/** + * jsPDF Context2D PlugIn Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv + * + * Licensed under the MIT License. http://opensource.org/licenses/mit-license + */ + +/** + * This plugin mimics the HTML5 Canvas's context2d. + * + * The goal is to provide a way for current canvas implementations to print directly to a PDF. + */ + +/** + * TODO implement stroke opacity (refactor from fill() method ) + * TODO transform angle and radii parameters + */ + +/** + * require('jspdf.js'); require('lib/css_colors.js'); + */ + +(function (jsPDFAPI) { + 'use strict'; + + jsPDFAPI.events.push(['initialized', function () { + this.context2d.pdf = this; + this.context2d.internal.pdf = this; + this.context2d.ctx = new context(); + this.context2d.ctxStack = []; + this.context2d.path = []; + }]); + + jsPDFAPI.context2d = { + pageWrapXEnabled: false, + pageWrapYEnabled: false, + pageWrapX: 9999999, + pageWrapY: 9999999, + ctx: new context(), + f2: function f2(number) { + return number.toFixed(2); + }, + + fillRect: function fillRect(x, y, w, h) { + if (this._isFillTransparent()) { + return; + } + x = this._wrapX(x); + y = this._wrapY(y); + + var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); + this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f"); + }, + + strokeRect: function strokeRect(x, y, w, h) { + if (this._isStrokeTransparent()) { + return; + } + x = this._wrapX(x); + y = this._wrapY(y); + + var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); + this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "s"); + }, + + /** + * We cannot clear PDF commands that were already written to PDF, so we use white instead.
    + * As a special case, read a special flag (ignoreClearRect) and do nothing if it is set. + * This results in all calls to clearRect() to do nothing, and keep the canvas transparent. + * This flag is stored in the save/restore context and is managed the same way as other drawing states. + * @param x + * @param y + * @param w + * @param h + */ + clearRect: function clearRect(x, y, w, h) { + if (this.ctx.ignoreClearRect) { + return; + } + + x = this._wrapX(x); + y = this._wrapY(y); + + var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); + this.save(); + this.setFillStyle('#ffffff'); + //TODO This is hack to fill with white. + this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f"); + this.restore(); + }, + + save: function save() { + this.ctx._fontSize = this.pdf.internal.getFontSize(); + var ctx = new context(); + ctx.copy(this.ctx); + this.ctxStack.push(this.ctx); + this.ctx = ctx; + }, + + restore: function restore() { + this.ctx = this.ctxStack.pop(); + this.setFillStyle(this.ctx.fillStyle); + this.setStrokeStyle(this.ctx.strokeStyle); + this.setFont(this.ctx.font); + this.pdf.setFontSize(this.ctx._fontSize); + this.setLineCap(this.ctx.lineCap); + this.setLineWidth(this.ctx.lineWidth); + this.setLineJoin(this.ctx.lineJoin); + }, + + rect: function rect(x, y, w, h) { + this.moveTo(x, y); + this.lineTo(x + w, y); + this.lineTo(x + w, y + h); + this.lineTo(x, y + h); + this.lineTo(x, y); //TODO not needed + this.closePath(); + }, + + beginPath: function beginPath() { + this.path = []; + }, + + closePath: function closePath() { + this.path.push({ + type: 'close' + }); + }, + + _getRgba: function _getRgba(style) { + // get the decimal values of r, g, and b; + var rgba = {}; + + if (this.internal.rxTransparent.test(style)) { + rgba.r = 0; + rgba.g = 0; + rgba.b = 0; + rgba.a = 0; + } else { + var m = this.internal.rxRgb.exec(style); + if (m != null) { + rgba.r = parseInt(m[1]); + rgba.g = parseInt(m[2]); + rgba.b = parseInt(m[3]); + rgba.a = 1; + } else { + m = this.internal.rxRgba.exec(style); + if (m != null) { + rgba.r = parseInt(m[1]); + rgba.g = parseInt(m[2]); + rgba.b = parseInt(m[3]); + rgba.a = parseFloat(m[4]); + } else { + rgba.a = 1; + if (style.charAt(0) != '#') { + style = CssColors.colorNameToHex(style); + if (!style) { + style = '#000000'; + } + } else {} + + if (style.length === 4) { + rgba.r = style.substring(1, 2); + rgba.r += r; + rgba.g = style.substring(2, 3); + rgba.g += g; + rgba.b = style.substring(3, 4); + rgba.b += b; + } else { + rgba.r = style.substring(1, 3); + rgba.g = style.substring(3, 5); + rgba.b = style.substring(5, 7); + } + rgba.r = parseInt(rgba.r, 16); + rgba.g = parseInt(rgba.g, 16); + rgba.b = parseInt(rgba.b, 16); + } + } + } + rgba.style = style; + return rgba; + }, + + setFillStyle: function setFillStyle(style) { + // get the decimal values of r, g, and b; + var r, g, b, a; + + if (this.internal.rxTransparent.test(style)) { + r = 0; + g = 0; + b = 0; + a = 0; + } else { + var m = this.internal.rxRgb.exec(style); + if (m != null) { + r = parseInt(m[1]); + g = parseInt(m[2]); + b = parseInt(m[3]); + a = 1; + } else { + m = this.internal.rxRgba.exec(style); + if (m != null) { + r = parseInt(m[1]); + g = parseInt(m[2]); + b = parseInt(m[3]); + a = parseFloat(m[4]); + } else { + a = 1; + if (style.charAt(0) != '#') { + style = CssColors.colorNameToHex(style); + if (!style) { + style = '#000000'; + } + } else {} + + if (style.length === 4) { + r = style.substring(1, 2); + r += r; + g = style.substring(2, 3); + g += g; + b = style.substring(3, 4); + b += b; + } else { + r = style.substring(1, 3); + g = style.substring(3, 5); + b = style.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + } + } + + this.ctx.fillStyle = style; + this.ctx._isFillTransparent = a == 0; + this.ctx._fillOpacity = a; + + this.pdf.setFillColor(r, g, b, { + a: a + }); + this.pdf.setTextColor(r, g, b, { + a: a + }); + }, + + setStrokeStyle: function setStrokeStyle(style) { + var rgba = this._getRgba(style); + + this.ctx.strokeStyle = rgba.style; + this.ctx._isStrokeTransparent = rgba.a == 0; + this.ctx._strokeOpacity = rgba.a; + + //TODO jsPDF to handle rgba + if (rgba.a === 0) { + this.pdf.setDrawColor(255, 255, 255); + } else if (rgba.a === 1) { + this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b); + } else { + //this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b, {a: rgba.a}); + this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b); + } + }, + + fillText: function fillText(text, x, y, maxWidth) { + if (this._isFillTransparent()) { + return; + } + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + var rads = this._matrix_rotation(this.ctx._transform); + var degs = rads * 57.2958; + + //TODO only push the clip if it has not been applied to the current PDF context + if (this.ctx._clip_path.length > 0) { + var lines; + if (window.outIntercept) { + lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; + } else { + lines = this.pdf.internal.pages[1]; + } + lines.push("q"); + var origPath = this.path; + this.path = this.ctx._clip_path; + this.ctx._clip_path = []; + this._fill(null, true); + this.ctx._clip_path = this.path; + this.path = origPath; + } + + this.pdf.text(text, x, this._getBaseline(y), null, degs); + + if (this.ctx._clip_path.length > 0) { + lines.push('Q'); + } + }, + + strokeText: function strokeText(text, x, y, maxWidth) { + if (this._isStrokeTransparent()) { + return; + } + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + var rads = this._matrix_rotation(this.ctx._transform); + var degs = rads * 57.2958; + + //TODO only push the clip if it has not been applied to the current PDF context + if (this.ctx._clip_path.length > 0) { + var lines; + if (window.outIntercept) { + lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; + } else { + lines = this.pdf.internal.pages[1]; + } + lines.push("q"); + var origPath = this.path; + this.path = this.ctx._clip_path; + this.ctx._clip_path = []; + this._fill(null, true); + this.ctx._clip_path = this.path; + this.path = origPath; + } + + this.pdf.text(text, x, this._getBaseline(y), { + stroke: true + }, degs); + + if (this.ctx._clip_path.length > 0) { + lines.push('Q'); + } + }, + + setFont: function setFont(font) { + this.ctx.font = font; + + //var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+["']?(\w+)['"]?/; + var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+(.*)?/; + m = rx.exec(font); + if (m != null) { + var fontStyle = m[1]; + var fontVariant = m[2]; + var fontWeight = m[3]; + var fontSize = m[4]; + var fontSizeUnit = m[5]; + var fontFamily = m[6]; + + if ('px' === fontSizeUnit) { + fontSize = Math.floor(parseFloat(fontSize)); + // fontSize = fontSize * 1.25; + } else if ('em' === fontSizeUnit) { + fontSize = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize()); + } else { + fontSize = Math.floor(parseFloat(fontSize)); + } + + this.pdf.setFontSize(fontSize); + + if (fontWeight === 'bold' || fontWeight === '700') { + this.pdf.setFontStyle('bold'); + } else { + if (fontStyle === 'italic') { + this.pdf.setFontStyle('italic'); + } else { + this.pdf.setFontStyle('normal'); + } + } + + var name = fontFamily; + var parts = name.toLowerCase().split(/\s*,\s*/); + var jsPdfFontName; + + if (parts.indexOf('arial') != -1) { + jsPdfFontName = 'Arial'; + } else if (parts.indexOf('verdana') != -1) { + jsPdfFontName = 'Verdana'; + } else if (parts.indexOf('helvetica') != -1) { + jsPdfFontName = 'Helvetica'; + } else if (parts.indexOf('sans-serif') != -1) { + jsPdfFontName = 'sans-serif'; + } else if (parts.indexOf('fixed') != -1) { + jsPdfFontName = 'Fixed'; + } else if (parts.indexOf('monospace') != -1) { + jsPdfFontName = 'Monospace'; + } else if (parts.indexOf('terminal') != -1) { + jsPdfFontName = 'Terminal'; + } else if (parts.indexOf('courier') != -1) { + jsPdfFontName = 'Courier'; + } else if (parts.indexOf('times') != -1) { + jsPdfFontName = 'Times'; + } else if (parts.indexOf('cursive') != -1) { + jsPdfFontName = 'Cursive'; + } else if (parts.indexOf('fantasy') != -1) { + jsPdfFontName = 'Fantasy'; + } else if (parts.indexOf('serif') != -1) { + jsPdfFontName = 'Serif'; + } else { + jsPdfFontName = 'Serif'; + } + + //TODO check more cases + var style; + if ('bold' === fontWeight) { + style = 'bold'; + } else { + style = 'normal'; + } + + this.pdf.setFont(jsPdfFontName, style); + } else { + var rx = /(\d+)(pt|px|em)\s+(\w+)\s*(\w+)?/; + var m = rx.exec(font); + if (m != null) { + var size = m[1]; + var unit = m[2]; + var name = m[3]; + var style = m[4]; + if (!style) { + style = 'normal'; + } + if ('em' === fontSizeUnit) { + size = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize()); + } else { + size = Math.floor(parseFloat(size)); + } + this.pdf.setFontSize(size); + this.pdf.setFont(name, style); + } + } + }, + + setTextBaseline: function setTextBaseline(baseline) { + this.ctx.textBaseline = baseline; + }, + + getTextBaseline: function getTextBaseline() { + return this.ctx.textBaseline; + }, + + //TODO implement textAlign + setTextAlign: function setTextAlign(align) { + this.ctx.textAlign = align; + }, + + getTextAlign: function getTextAlign() { + return this.ctx.textAlign; + }, + + setLineWidth: function setLineWidth(width) { + this.ctx.lineWidth = width; + this.pdf.setLineWidth(width); + }, + + setLineCap: function setLineCap(style) { + this.ctx.lineCap = style; + this.pdf.setLineCap(style); + }, + + setLineJoin: function setLineJoin(style) { + this.ctx.lineJoin = style; + this.pdf.setLineJoin(style); + }, + + moveTo: function moveTo(x, y) { + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + + var obj = { + type: 'mt', + x: x, + y: y + }; + this.path.push(obj); + }, + + _wrapX: function _wrapX(x) { + if (this.pageWrapXEnabled) { + return x % this.pageWrapX; + } else { + return x; + } + }, + + _wrapY: function _wrapY(y) { + if (this.pageWrapYEnabled) { + this._gotoPage(this._page(y)); + return (y - this.lastBreak) % this.pageWrapY; + } else { + return y; + } + }, + + transform: function transform(a, b, c, d, e, f) { + //TODO apply to current transformation instead of replacing + this.ctx._transform = [a, b, c, d, e, f]; + }, + + setTransform: function setTransform(a, b, c, d, e, f) { + this.ctx._transform = [a, b, c, d, e, f]; + }, + + _getTransform: function _getTransform() { + return this.ctx._transform; + }, + + lastBreak: 0, + // Y Position of page breaks. + pageBreaks: [], + // returns: One-based Page Number + // Should only be used if pageWrapYEnabled is true + _page: function _page(y) { + if (this.pageWrapYEnabled) { + this.lastBreak = 0; + var manualBreaks = 0; + var autoBreaks = 0; + for (var i = 0; i < this.pageBreaks.length; i++) { + if (y >= this.pageBreaks[i]) { + manualBreaks++; + if (this.lastBreak === 0) { + autoBreaks++; + } + var spaceBetweenLastBreak = this.pageBreaks[i] - this.lastBreak; + this.lastBreak = this.pageBreaks[i]; + var pagesSinceLastBreak = Math.floor(spaceBetweenLastBreak / this.pageWrapY); + autoBreaks += pagesSinceLastBreak; + } + } + if (this.lastBreak === 0) { + var pagesSinceLastBreak = Math.floor(y / this.pageWrapY) + 1; + autoBreaks += pagesSinceLastBreak; + } + return autoBreaks + manualBreaks; + } else { + return this.pdf.internal.getCurrentPageInfo().pageNumber; + } + }, + + _gotoPage: function _gotoPage(pageOneBased) { + // This is a stub to be overriden if needed + }, + + lineTo: function lineTo(x, y) { + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + + var obj = { + type: 'lt', + x: x, + y: y + }; + this.path.push(obj); + }, + + bezierCurveTo: function bezierCurveTo(x1, y1, x2, y2, x, y) { + x1 = this._wrapX(x1); + y1 = this._wrapY(y1); + x2 = this._wrapX(x2); + y2 = this._wrapY(y2); + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt; + xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]); + x1 = xpt[0]; + y1 = xpt[1]; + xpt = this._matrix_map_point(this.ctx._transform, [x2, y2]); + x2 = xpt[0]; + y2 = xpt[1]; + + var obj = { + type: 'bct', + x1: x1, + y1: y1, + x2: x2, + y2: y2, + x: x, + y: y + }; + this.path.push(obj); + }, + + quadraticCurveTo: function quadraticCurveTo(x1, y1, x, y) { + x1 = this._wrapX(x1); + y1 = this._wrapY(y1); + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt; + xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]); + x1 = xpt[0]; + y1 = xpt[1]; + + var obj = { + type: 'qct', + x1: x1, + y1: y1, + x: x, + y: y + }; + this.path.push(obj); + }, + + arc: function arc(x, y, radius, startAngle, endAngle, anticlockwise) { + x = this._wrapX(x); + y = this._wrapY(y); + + var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); + x = xpt[0]; + y = xpt[1]; + + var obj = { + type: 'arc', + x: x, + y: y, + radius: radius, + startAngle: startAngle, + endAngle: endAngle, + anticlockwise: anticlockwise + }; + this.path.push(obj); + }, + + drawImage: function drawImage(img, x, y, w, h, x2, y2, w2, h2) { + if (x2 !== undefined) { + x = x2; + y = y2; + w = w2; + h = h2; + } + x = this._wrapX(x); + y = this._wrapY(y); + + var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); + var xRect2 = this._matrix_map_rect(this.ctx._transform, { x: x2, y: y2, w: w2, h: h2 }); + + // TODO implement source clipping and image scaling + var format; + var rx = /data:image\/(\w+).*/i; + var m = rx.exec(img); + if (m != null) { + format = m[1]; + } else { + // format = "jpeg"; + format = "png"; + } + + this.pdf.addImage(img, format, xRect.x, xRect.y, xRect.w, xRect.h); + }, + + /** + * Multiply the first matrix by the second + * @param m1 + * @param m2 + * @returns {*[]} + * @private + */ + _matrix_multiply: function _matrix_multiply(m2, m1) { + var sx = m1[0]; + var shy = m1[1]; + var shx = m1[2]; + var sy = m1[3]; + var tx = m1[4]; + var ty = m1[5]; + + var t0 = sx * m2[0] + shy * m2[2]; + var t2 = shx * m2[0] + sy * m2[2]; + var t4 = tx * m2[0] + ty * m2[2] + m2[4]; + shy = sx * m2[1] + shy * m2[3]; + sy = shx * m2[1] + sy * m2[3]; + ty = tx * m2[1] + ty * m2[3] + m2[5]; + sx = t0; + shx = t2; + tx = t4; + + return [sx, shy, shx, sy, tx, ty]; + }, + + _matrix_rotation: function _matrix_rotation(m) { + return Math.atan2(m[2], m[0]); + }, + + _matrix_decompose: function _matrix_decompose(matrix) { + + var a = matrix[0]; + var b = matrix[1]; + var c = matrix[2]; + var d = matrix[3]; + + var scaleX = Math.sqrt(a * a + b * b); + a /= scaleX; + b /= scaleX; + + var shear = a * c + b * d; + c -= a * shear; + d -= b * shear; + + var scaleY = Math.sqrt(c * c + d * d); + c /= scaleY; + d /= scaleY; + shear /= scaleY; + + if (a * d < b * c) { + a = -a; + b = -b; + shear = -shear; + scaleX = -scaleX; + } + + return { + scale: [scaleX, 0, 0, scaleY, 0, 0], + translate: [1, 0, 0, 1, matrix[4], matrix[5]], + rotate: [a, b, -b, a, 0, 0], + skew: [1, 0, shear, 1, 0, 0] + }; + }, + + _matrix_map_point: function _matrix_map_point(m1, pt) { + var sx = m1[0]; + var shy = m1[1]; + var shx = m1[2]; + var sy = m1[3]; + var tx = m1[4]; + var ty = m1[5]; + + var px = pt[0]; + var py = pt[1]; + + var x = px * sx + py * shx + tx; + var y = px * shy + py * sy + ty; + return [x, y]; + }, + + _matrix_map_point_obj: function _matrix_map_point_obj(m1, pt) { + var xpt = this._matrix_map_point(m1, [pt.x, pt.y]); + return { x: xpt[0], y: xpt[1] }; + }, + + _matrix_map_rect: function _matrix_map_rect(m1, rect) { + var p1 = this._matrix_map_point(m1, [rect.x, rect.y]); + var p2 = this._matrix_map_point(m1, [rect.x + rect.w, rect.y + rect.h]); + return { x: p1[0], y: p1[1], w: p2[0] - p1[0], h: p2[1] - p1[1] }; + }, + + _matrix_is_identity: function _matrix_is_identity(m1) { + if (m1[0] != 1) { + return false; + } + if (m1[1] != 0) { + return false; + } + if (m1[2] != 0) { + return false; + } + if (m1[3] != 1) { + return false; + } + if (m1[4] != 0) { + return false; + } + if (m1[5] != 0) { + return false; + } + return true; + }, + + rotate: function rotate(angle) { + var matrix = [Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0.0, 0.0]; + this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix); + }, + + scale: function scale(sx, sy) { + var matrix = [sx, 0.0, 0.0, sy, 0.0, 0.0]; + this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix); + }, + + translate: function translate(x, y) { + var matrix = [1.0, 0.0, 0.0, 1.0, x, y]; + this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix); + }, + + stroke: function stroke() { + if (this.ctx._clip_path.length > 0) { + + var lines; + if (window.outIntercept) { + lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; + } else { + lines = this.pdf.internal.pages[1]; + } + lines.push("q"); + + var origPath = this.path; + this.path = this.ctx._clip_path; + this.ctx._clip_path = []; + this._stroke(true); + + this.ctx._clip_path = this.path; + this.path = origPath; + this._stroke(false); + + lines.push("Q"); + } else { + this._stroke(false); + } + }, + + _stroke: function _stroke(isClip) { + if (!isClip && this._isStrokeTransparent()) { + return; + } + + //TODO opacity + + var moves = []; + var closed = false; + + var xPath = this.path; + + for (var i = 0; i < xPath.length; i++) { + var pt = xPath[i]; + switch (pt.type) { + case 'mt': + moves.push({ start: pt, deltas: [], abs: [] }); + break; + case 'lt': + var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; + moves[moves.length - 1].deltas.push(delta); + moves[moves.length - 1].abs.push(pt); + break; + case 'bct': + var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; + moves[moves.length - 1].deltas.push(delta); + break; + case 'qct': + // convert to bezier + var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x); + var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y); + var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x); + var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y); + var x3 = pt.x; + var y3 = pt.y; + var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y]; + moves[moves.length - 1].deltas.push(delta); + break; + case 'arc': + moves[moves.length - 1].arc = true; + moves[moves.length - 1].abs.push(pt); + break; + case 'close': + closed = true; + break; + } + } + + for (var i = 0; i < moves.length; i++) { + var style; + if (i == moves.length - 1) { + style = 's'; + } else { + style = null; + } + if (moves[i].arc) { + var arcs = moves[i].abs; + for (var ii = 0; ii < arcs.length; ii++) { + var arc = arcs[ii]; + var start = arc.startAngle * 360 / (2 * Math.PI); + var end = arc.endAngle * 360 / (2 * Math.PI); + var x = arc.x; + var y = arc.y; + this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, style, isClip); + } + } else { + var x = moves[i].start.x; + var y = moves[i].start.y; + if (!isClip) { + this.pdf.lines(moves[i].deltas, x, y, null, style); + } else { + this.pdf.lines(moves[i].deltas, x, y, null, null); + this.pdf.clip_fixed(); + } + } + } + }, + + _isFillTransparent: function _isFillTransparent() { + return this.ctx._isFillTransparent || this.globalAlpha == 0; + }, + + _isStrokeTransparent: function _isStrokeTransparent() { + return this.ctx._isStrokeTransparent || this.globalAlpha == 0; + }, + + fill: function fill(fillRule) { + //evenodd or nonzero (default) + if (this.ctx._clip_path.length > 0) { + + var lines; + if (window.outIntercept) { + lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; + } else { + lines = this.pdf.internal.pages[1]; + } + lines.push("q"); + + var origPath = this.path; + this.path = this.ctx._clip_path; + this.ctx._clip_path = []; + this._fill(fillRule, true); + + this.ctx._clip_path = this.path; + this.path = origPath; + this._fill(fillRule, false); + + lines.push('Q'); + } else { + this._fill(fillRule, false); + } + }, + + _fill: function _fill(fillRule, isClip) { + if (this._isFillTransparent()) { + return; + } + var v2Support = typeof this.pdf.internal.newObject2 === 'function'; + + var lines; + if (window.outIntercept) { + lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; + } else { + lines = this.pdf.internal.pages[1]; + } + + // if (this.ctx._clip_path.length > 0) { + // lines.push('q'); + // var oldPath = this.path; + // this.path = this.ctx._clip_path; + // this.ctx._clip_path = []; + // this._fill(fillRule, true); + // this.ctx._clip_path = this.path; + // this.path = oldPath; + // } + + var moves = []; + var outInterceptOld = window.outIntercept; + + if (v2Support) { + // Blend and Mask + switch (this.ctx.globalCompositeOperation) { + case 'normal': + case 'source-over': + break; + case 'destination-in': + case 'destination-out': + //TODO this need to be added to the current group or page + // define a mask stream + var obj = this.pdf.internal.newStreamObject(); + + // define a mask state + var obj2 = this.pdf.internal.newObject2(); + obj2.push('<>'); // /S /Luminosity will need to define color space + obj2.push('>>'); + + // add mask to page resources + var gsName = 'MASK' + obj2.objId; + this.pdf.internal.addGraphicsState(gsName, obj2.objId); + + var instruction = '/' + gsName + ' gs'; + // add mask to page, group, or stream + lines.splice(0, 0, 'q'); + lines.splice(1, 0, instruction); + lines.push('Q'); + + window.outIntercept = obj; + break; + default: + var dictionaryEntry = '/' + this.pdf.internal.blendModeMap[this.ctx.globalCompositeOperation.toUpperCase()]; + if (dictionaryEntry) { + this.pdf.internal.out(dictionaryEntry + ' gs'); + } + break; + } + } + + var alpha = this.ctx.globalAlpha; + if (this.ctx._fillOpacity < 1) { + // TODO combine this with global opacity + alpha = this.ctx._fillOpacity; + } + + //TODO check for an opacity graphics state that was already created + //TODO do not set opacity if current value is already active + if (v2Support) { + var objOpac = this.pdf.internal.newObject2(); + objOpac.push('<>'); + var gsName = 'GS_O_' + objOpac.objId; + this.pdf.internal.addGraphicsState(gsName, objOpac.objId); + this.pdf.internal.out('/' + gsName + ' gs'); + } + + var xPath = this.path; + + for (var i = 0; i < xPath.length; i++) { + var pt = xPath[i]; + switch (pt.type) { + case 'mt': + moves.push({ start: pt, deltas: [], abs: [] }); + break; + case 'lt': + var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; + moves[moves.length - 1].deltas.push(delta); + moves[moves.length - 1].abs.push(pt); + break; + case 'bct': + var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; + moves[moves.length - 1].deltas.push(delta); + break; + case 'qct': + // convert to bezier + var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x); + var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y); + var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x); + var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y); + var x3 = pt.x; + var y3 = pt.y; + var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y]; + moves[moves.length - 1].deltas.push(delta); + break; + case 'arc': + //TODO this was hack to avoid out of bounds issue + if (moves.length == 0) { + moves.push({ start: { x: 0, y: 0 }, deltas: [], abs: [] }); + } + moves[moves.length - 1].arc = true; + moves[moves.length - 1].abs.push(pt); + break; + case 'close': + //moves[moves.length - 1].deltas.push('close'); + break; + } + } + + for (var i = 0; i < moves.length; i++) { + var style; + if (i == moves.length - 1) { + style = 'f'; + if (fillRule === 'evenodd') { + style += '*'; + } + } else { + style = null; + } + + if (moves[i].arc) { + var arcs = moves[i].abs; + for (var ii = 0; ii < arcs.length; ii++) { + var arc = arcs[ii]; + //TODO lines deltas were getting in here + if (typeof arc.startAngle !== 'undefined') { + var start = arc.startAngle * 360 / (2 * Math.PI); + var end = arc.endAngle * 360 / (2 * Math.PI); + // Add the current position (last move to) + //var x = moves[i].start.x + arc.x; + //var y = moves[i].start.y + arc.y; + var x = arc.x; + var y = arc.y; + if (ii == 0) { + this.internal.move2(this, x, y); + } + this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, null, isClip); + } else { + this.internal.line2(c2d, arc.x, arc.y); + } + } + + // extra move bug causing close to resolve to wrong point + var x = moves[i].start.x; + var y = moves[i].start.y; + this.internal.line2(c2d, x, y); + + this.pdf.internal.out('h'); + this.pdf.internal.out('f'); + } else { + var x = moves[i].start.x; + var y = moves[i].start.y; + if (!isClip) { + this.pdf.lines(moves[i].deltas, x, y, null, style); + } else { + this.pdf.lines(moves[i].deltas, x, y, null, null); + this.pdf.clip_fixed(); + } + } + } + + window.outIntercept = outInterceptOld; + + // if (this.ctx._clip_path.length > 0) { + // lines.push('Q'); + // } + }, + + pushMask: function pushMask() { + var v2Support = typeof this.pdf.internal.newObject2 === 'function'; + + if (!v2Support) { + console.log('jsPDF v2 not enabled'); + return; + } + + // define a mask stream + var obj = this.pdf.internal.newStreamObject(); + + // define a mask state + var obj2 = this.pdf.internal.newObject2(); + obj2.push('<>'); // /S /Luminosity will need to define color space + obj2.push('>>'); + + // add mask to page resources + var gsName = 'MASK' + obj2.objId; + this.pdf.internal.addGraphicsState(gsName, obj2.objId); + + var instruction = '/' + gsName + ' gs'; + this.pdf.internal.out(instruction); + }, + + clip: function clip() { + //TODO do we reset the path, or just copy it? + if (this.ctx._clip_path.length > 0) { + for (var i = 0; i < this.path.length; i++) { + this.ctx._clip_path.push(this.path[i]); + } + } else { + this.ctx._clip_path = this.path; + } + this.path = []; + }, + + measureText: function measureText(text) { + var pdf = this.pdf; + return { + getWidth: function getWidth() { + var fontSize = pdf.internal.getFontSize(); + var txtWidth = pdf.getStringUnitWidth(text) * fontSize / pdf.internal.scaleFactor; + return txtWidth; + }, + + get width() { + return this.getWidth(text); + } + }; + }, + _getBaseline: function _getBaseline(y) { + var height = parseInt(this.pdf.internal.getFontSize()); + // TODO Get descent from font descriptor + var descent = height * .25; + switch (this.ctx.textBaseline) { + case 'bottom': + return y - descent; + case 'top': + return y + height; + case 'hanging': + return y + height - descent; + case 'middle': + return y + height / 2 - descent; + case 'ideographic': + // TODO not implemented + return y; + case 'alphabetic': + default: + return y; + } + } + }; + + var c2d = jsPDFAPI.context2d; + + // accessor methods + Object.defineProperty(c2d, 'fillStyle', { + set: function set(value) { + this.setFillStyle(value); + }, + get: function get() { + return this.ctx.fillStyle; + } + }); + Object.defineProperty(c2d, 'strokeStyle', { + set: function set(value) { + this.setStrokeStyle(value); + }, + get: function get() { + return this.ctx.strokeStyle; + } + }); + Object.defineProperty(c2d, 'lineWidth', { + set: function set(value) { + this.setLineWidth(value); + }, + get: function get() { + return this.ctx.lineWidth; + } + }); + Object.defineProperty(c2d, 'lineCap', { + set: function set(val) { + this.setLineCap(val); + }, + get: function get() { + return this.ctx.lineCap; + } + }); + Object.defineProperty(c2d, 'lineJoin', { + set: function set(val) { + this.setLineJoin(val); + }, + get: function get() { + return this.ctx.lineJoin; + } + }); + Object.defineProperty(c2d, 'miterLimit', { + set: function set(val) { + this.ctx.miterLimit = val; + }, + get: function get() { + return this.ctx.miterLimit; + } + }); + Object.defineProperty(c2d, 'textBaseline', { + set: function set(value) { + this.setTextBaseline(value); + }, + get: function get() { + return this.getTextBaseline(); + } + }); + Object.defineProperty(c2d, 'textAlign', { + set: function set(value) { + this.setTextAlign(value); + }, + get: function get() { + return this.getTextAlign(); + } + }); + Object.defineProperty(c2d, 'font', { + set: function set(value) { + this.setFont(value); + }, + get: function get() { + return this.ctx.font; + } + }); + Object.defineProperty(c2d, 'globalCompositeOperation', { + set: function set(value) { + this.ctx.globalCompositeOperation = value; + }, + get: function get() { + return this.ctx.globalCompositeOperation; + } + }); + Object.defineProperty(c2d, 'globalAlpha', { + set: function set(value) { + this.ctx.globalAlpha = value; + }, + get: function get() { + return this.ctx.globalAlpha; + } + }); + // Not HTML API + Object.defineProperty(c2d, 'ignoreClearRect', { + set: function set(value) { + this.ctx.ignoreClearRect = value; + }, + get: function get() { + return this.ctx.ignoreClearRect; + } + }); + // End Not HTML API + + c2d.internal = {}; + + c2d.internal.rxRgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/; + c2d.internal.rxRgba = /rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/; + c2d.internal.rxTransparent = /transparent|rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*0+\s*\)/; + + // http://hansmuller-flex.blogspot.com/2011/10/more-about-approximating-circular-arcs.html + c2d.internal.arc = function (c2d, xc, yc, r, a1, a2, anticlockwise, style) { + var includeMove = true; + + var k = this.pdf.internal.scaleFactor; + var pageHeight = this.pdf.internal.pageSize.height; + var f2 = this.pdf.internal.f2; + + var a1r = a1 * (Math.PI / 180); + var a2r = a2 * (Math.PI / 180); + var curves = this.createArc(r, a1r, a2r, anticlockwise); + var pathData = null; + + for (var i = 0; i < curves.length; i++) { + var curve = curves[i]; + if (includeMove && i == 0) { + this.pdf.internal.out([f2((curve.x1 + xc) * k), f2((pageHeight - (curve.y1 + yc)) * k), 'm', f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'].join(' ')); + } else { + this.pdf.internal.out([f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'].join(' ')); + } + + //c2d._lastPoint = {x: curve.x1 + xc, y: curve.y1 + yc}; + c2d._lastPoint = { x: xc, y: yc }; + // f2((curve.x1 + xc) * k), f2((pageHeight - (curve.y1 + yc)) * k), 'm', f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c' + } + + if (style !== null) { + this.pdf.internal.out(this.pdf.internal.getStyle(style)); + } + }; + + /** + * + * @param x Edge point X + * @param y Edge point Y + * @param r Radius + * @param a1 start angle + * @param a2 end angle + * @param anticlockwise + * @param style + * @param isClip + */ + c2d.internal.arc2 = function (c2d, x, y, r, a1, a2, anticlockwise, style, isClip) { + // we need to convert from cartesian to polar here methinks. + var centerX = x; // + r; + var centerY = y; + + if (!isClip) { + this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, style); + } else { + this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, null); + this.pdf.clip_fixed(); + } + }; + + c2d.internal.move2 = function (c2d, x, y) { + var k = this.pdf.internal.scaleFactor; + var pageHeight = this.pdf.internal.pageSize.height; + var f2 = this.pdf.internal.f2; + + this.pdf.internal.out([f2(x * k), f2((pageHeight - y) * k), 'm'].join(' ')); + c2d._lastPoint = { x: x, y: y }; + }; + + c2d.internal.line2 = function (c2d, dx, dy) { + var k = this.pdf.internal.scaleFactor; + var pageHeight = this.pdf.internal.pageSize.height; + var f2 = this.pdf.internal.f2; + + //var pt = {x: c2d._lastPoint.x + dx, y: c2d._lastPoint.y + dy}; + var pt = { x: dx, y: dy }; + + this.pdf.internal.out([f2(pt.x * k), f2((pageHeight - pt.y) * k), 'l'].join(' ')); + //this.pdf.internal.out('f'); + c2d._lastPoint = pt; + }; + + /** + * Return a array of objects that represent bezier curves which approximate the circular arc centered at the origin, from startAngle to endAngle (radians) with the specified radius. + * + * Each bezier curve is an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cubic bezier's control points. + */ + + c2d.internal.createArc = function (radius, startAngle, endAngle, anticlockwise) { + + var EPSILON = 0.00001; // Roughly 1/1000th of a degree, see below + + // normalize startAngle, endAngle to [-2PI, 2PI] + var twoPI = Math.PI * 2; + var startAngleN = startAngle; + if (startAngleN < twoPI || startAngleN > twoPI) { + startAngleN = startAngleN % twoPI; + } + var endAngleN = endAngle; + if (endAngleN < twoPI || endAngleN > twoPI) { + endAngleN = endAngleN % twoPI; + } + + // Compute the sequence of arc curves, up to PI/2 at a time. + // Total arc angle is less than 2PI. + var curves = []; + var piOverTwo = Math.PI / 2.0; + // var sgn = (startAngle < endAngle) ? +1 : -1; // clockwise or counterclockwise + var sgn = anticlockwise ? -1 : +1; + + var a1 = startAngle; + for (var totalAngle = Math.min(twoPI, Math.abs(endAngleN - startAngleN)); totalAngle > EPSILON;) { + var a2 = a1 + sgn * Math.min(totalAngle, piOverTwo); + curves.push(this.createSmallArc(radius, a1, a2)); + totalAngle -= Math.abs(a2 - a1); + a1 = a2; + } + + return curves; + }; + + /** + * Cubic bezier approximation of a circular arc centered at the origin, from (radians) a1 to a2, where a2-a1 < pi/2. The arc's radius is r. + * + * Returns an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cubic bezier's control points. + * + * This algorithm is based on the approach described in: A. Riškus, "Approximation of a Cubic Bezier Curve by Circular Arcs and Vice Versa," Information Technology and Control, 35(4), 2006 pp. 371-378. + */ + + c2d.internal.createSmallArc = function (r, a1, a2) { + // Compute all four points for an arc that subtends the same total angle + // but is centered on the X-axis + + var a = (a2 - a1) / 2.0; + + var x4 = r * Math.cos(a); + var y4 = r * Math.sin(a); + var x1 = x4; + var y1 = -y4; + + var q1 = x1 * x1 + y1 * y1; + var q2 = q1 + x1 * x4 + y1 * y4; + var k2 = 4 / 3 * (Math.sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4); + + var x2 = x1 - k2 * y1; + var y2 = y1 + k2 * x1; + var x3 = x2; + var y3 = -y2; + + // Find the arc points' actual locations by computing x1,y1 and x4,y4 + // and rotating the control points by a + a1 + + var ar = a + a1; + var cos_ar = Math.cos(ar); + var sin_ar = Math.sin(ar); + + return { + x1: r * Math.cos(a1), + y1: r * Math.sin(a1), + x2: x2 * cos_ar - y2 * sin_ar, + y2: x2 * sin_ar + y2 * cos_ar, + x3: x3 * cos_ar - y3 * sin_ar, + y3: x3 * sin_ar + y3 * cos_ar, + x4: r * Math.cos(a2), + y4: r * Math.sin(a2) + }; + }; + + function context() { + this._isStrokeTransparent = false; + this._strokeOpacity = 1; + this.strokeStyle = '#000000'; + this.fillStyle = '#000000'; + this._isFillTransparent = false; + this._fillOpacity = 1; + this.font = "12pt times"; + this.textBaseline = 'alphabetic'; // top,bottom,middle,ideographic,alphabetic,hanging + this.textAlign = 'start'; + this.lineWidth = 1; + this.lineJoin = 'miter'; // round, bevel, miter + this.lineCap = 'butt'; // butt, round, square + this._transform = [1, 0, 0, 1, 0, 0]; // sx, shy, shx, sy, tx, ty + this.globalCompositeOperation = 'normal'; + this.globalAlpha = 1.0; + this._clip_path = []; + // TODO miter limit //default 10 + + // Not HTML API + this.ignoreClearRect = false; + + this.copy = function (ctx) { + this._isStrokeTransparent = ctx._isStrokeTransparent; + this._strokeOpacity = ctx._strokeOpacity; + this.strokeStyle = ctx.strokeStyle; + this._isFillTransparent = ctx._isFillTransparent; + this._fillOpacity = ctx._fillOpacity; + this.fillStyle = ctx.fillStyle; + this.font = ctx.font; + this.lineWidth = ctx.lineWidth; + this.lineJoin = ctx.lineJoin; + this.lineCap = ctx.lineCap; + this.textBaseline = ctx.textBaseline; + this.textAlign = ctx.textAlign; + this._fontSize = ctx._fontSize; + this._transform = ctx._transform.slice(0); + this.globalCompositeOperation = ctx.globalCompositeOperation; + this.globalAlpha = ctx.globalAlpha; + this._clip_path = ctx._clip_path.slice(0); //TODO deep copy? + + // Not HTML API + this.ignoreClearRect = ctx.ignoreClearRect; + }; + } + + return this; +})(jsPDF.API); + +/** @preserve + * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser + * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com + * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria + * 2014 Diego Casorran, https://github.com/diegocr + * 2014 Daniel Husar, https://github.com/danielhusar + * 2014 Wolfgang Gassler, https://github.com/woolfg + * 2014 Steven Spungin, https://github.com/flamenco + * + * + * ==================================================================== + */ + +(function (jsPDFAPI) { + var clone, _DrillForContent, FontNameDB, FontStyleMap, TextAlignMap, FontWeightMap, FloatMap, ClearMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson; + clone = function () { + return function (obj) { + Clone.prototype = obj; + return new Clone(); + }; + function Clone() {} + }(); + PurgeWhiteSpace = function PurgeWhiteSpace(array) { + var fragment, i, l, lTrimmed, r, rTrimmed, trailingSpace; + i = 0; + l = array.length; + fragment = void 0; + lTrimmed = false; + rTrimmed = false; + while (!lTrimmed && i !== l) { + fragment = array[i] = array[i].trimLeft(); + if (fragment) { + lTrimmed = true; + } + i++; + } + i = l - 1; + while (l && !rTrimmed && i !== -1) { + fragment = array[i] = array[i].trimRight(); + if (fragment) { + rTrimmed = true; + } + i--; + } + r = /\s+$/g; + trailingSpace = true; + i = 0; + while (i !== l) { + // Leave the line breaks intact + if (array[i] != "\u2028") { + fragment = array[i].replace(/\s+/g, " "); + if (trailingSpace) { + fragment = fragment.trimLeft(); + } + if (fragment) { + trailingSpace = r.test(fragment); + } + array[i] = fragment; + } + i++; + } + return array; + }; + Renderer = function Renderer(pdf, x, y, settings) { + this.pdf = pdf; + this.x = x; + this.y = y; + this.settings = settings; + //list of functions which are called after each element-rendering process + this.watchFunctions = []; + this.init(); + return this; + }; + ResolveFont = function ResolveFont(css_font_family_string) { + var name, part, parts; + name = void 0; + parts = css_font_family_string.split(","); + part = parts.shift(); + while (!name && part) { + name = FontNameDB[part.trim().toLowerCase()]; + part = parts.shift(); + } + return name; + }; + ResolveUnitedNumber = function ResolveUnitedNumber(css_line_height_string) { + + //IE8 issues + css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string; + if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) { + css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px"; + } + if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) { + css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px"; + } + + var normal, undef, value; + undef = void 0; + normal = 16.00; + value = UnitedNumberMap[css_line_height_string]; + if (value) { + return value; + } + value = { + "xx-small": 9, + "x-small": 11, + small: 13, + medium: 16, + large: 19, + "x-large": 23, + "xx-large": 28, + auto: 0 + }[{ css_line_height_string: css_line_height_string }]; + + if (value !== undef) { + return UnitedNumberMap[css_line_height_string] = value / normal; + } + if (value = parseFloat(css_line_height_string)) { + return UnitedNumberMap[css_line_height_string] = value / normal; + } + value = css_line_height_string.match(/([\d\.]+)(px)/); + if (value.length === 3) { + return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal; + } + return UnitedNumberMap[css_line_height_string] = 1; + }; + GetCSS = function GetCSS(element) { + var css, tmp, computedCSSElement; + computedCSSElement = function (el) { + var compCSS; + compCSS = function (el) { + if (document.defaultView && document.defaultView.getComputedStyle) { + return document.defaultView.getComputedStyle(el, null); + } else if (el.currentStyle) { + return el.currentStyle; + } else { + return el.style; + } + }(el); + return function (prop) { + prop = prop.replace(/-\D/g, function (match) { + return match.charAt(1).toUpperCase(); + }); + return compCSS[prop]; + }; + }(element); + css = {}; + tmp = void 0; + css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times"; + css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal"; + css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left"; + tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal"; + if (tmp === "bold") { + if (css["font-style"] === "normal") { + css["font-style"] = tmp; + } else { + css["font-style"] = tmp + css["font-style"]; + } + } + css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1; + css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1; + css["display"] = computedCSSElement("display") === "inline" ? "inline" : "block"; + + tmp = css["display"] === "block"; + css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0; + css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0; + css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0; + css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0; + css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0; + css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0; + css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0; + css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0; + + css["page-break-before"] = computedCSSElement("page-break-before") || "auto"; + + //float and clearing of floats + css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none"; + css["clear"] = ClearMap[computedCSSElement("clear")] || "none"; + + css["color"] = computedCSSElement("color"); + + return css; + }; + elementHandledElsewhere = function elementHandledElsewhere(element, renderer, elementHandlers) { + var handlers, i, isHandledElsewhere, l, t; + isHandledElsewhere = false; + i = void 0; + l = void 0; + t = void 0; + handlers = elementHandlers["#" + element.id]; + if (handlers) { + if (typeof handlers === "function") { + isHandledElsewhere = handlers(element, renderer); + } else { + i = 0; + l = handlers.length; + while (!isHandledElsewhere && i !== l) { + isHandledElsewhere = handlers[i](element, renderer); + i++; + } + } + } + handlers = elementHandlers[element.nodeName]; + if (!isHandledElsewhere && handlers) { + if (typeof handlers === "function") { + isHandledElsewhere = handlers(element, renderer); + } else { + i = 0; + l = handlers.length; + while (!isHandledElsewhere && i !== l) { + isHandledElsewhere = handlers[i](element, renderer); + i++; + } + } + } + return isHandledElsewhere; + }; + tableToJson = function tableToJson(table, renderer) { + var data, headers, i, j, rowData, tableRow, table_obj, table_with, cell, l; + data = []; + headers = []; + i = 0; + l = table.rows[0].cells.length; + table_with = table.clientWidth; + while (i < l) { + cell = table.rows[0].cells[i]; + headers[i] = { + name: cell.textContent.toLowerCase().replace(/\s+/g, ''), + prompt: cell.textContent.replace(/\r?\n/g, ''), + width: cell.clientWidth / table_with * renderer.pdf.internal.pageSize.width + }; + i++; + } + i = 1; + while (i < table.rows.length) { + tableRow = table.rows[i]; + rowData = {}; + j = 0; + while (j < tableRow.cells.length) { + rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, ''); + j++; + } + data.push(rowData); + i++; + } + return table_obj = { + rows: data, + headers: headers + }; + }; + var SkipNode = { + SCRIPT: 1, + STYLE: 1, + NOSCRIPT: 1, + OBJECT: 1, + EMBED: 1, + SELECT: 1 + }; + var listCount = 1; + _DrillForContent = function DrillForContent(element, renderer, elementHandlers) { + var cn, cns, fragmentCSS, i, isBlock, l, px2pt, table2json, cb; + cns = element.childNodes; + cn = void 0; + fragmentCSS = GetCSS(element); + isBlock = fragmentCSS.display === "block"; + if (isBlock) { + renderer.setBlockBoundary(); + renderer.setBlockStyle(fragmentCSS); + } + px2pt = 0.264583 * 72 / 25.4; + i = 0; + l = cns.length; + while (i < l) { + cn = cns[i]; + if ((typeof cn === "undefined" ? "undefined" : _typeof(cn)) === "object") { + + //execute all watcher functions to e.g. reset floating + renderer.executeWatchFunctions(cn); + + /*** HEADER rendering **/ + if (cn.nodeType === 1 && cn.nodeName === 'HEADER') { + var header = cn; + //store old top margin + var oldMarginTop = renderer.pdf.margins_doc.top; + //subscribe for new page event and render header first on every page + renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) { + //set current y position to old margin + renderer.y = oldMarginTop; + //render all child nodes of the header element + _DrillForContent(header, renderer, elementHandlers); + //set margin to old margin + rendered header + 10 space to prevent overlapping + //important for other plugins (e.g. table) to start rendering at correct position after header + renderer.pdf.margins_doc.top = renderer.y + 10; + renderer.y += 10; + }, false); + } + + if (cn.nodeType === 8 && cn.nodeName === "#comment") { + if (~cn.textContent.indexOf("ADD_PAGE")) { + renderer.pdf.addPage(); + renderer.y = renderer.pdf.margins_doc.top; + } + } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) { + /*** IMAGE RENDERING ***/ + var cached_image; + if (cn.nodeName === "IMG") { + var url = cn.getAttribute("src"); + cached_image = images[renderer.pdf.sHashCode(url) || url]; + } + if (cached_image) { + if (renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height && renderer.y > renderer.pdf.margins_doc.top) { + renderer.pdf.addPage(); + renderer.y = renderer.pdf.margins_doc.top; + //check if we have to set back some values due to e.g. header rendering for new page + renderer.executeWatchFunctions(cn); + } + + var imagesCSS = GetCSS(cn); + var imageX = renderer.x; + var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor; + + //define additional paddings, margins which have to be taken into account for margin calculations + var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"]) * fontToUnitRatio; + var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"]) * fontToUnitRatio; + var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"]) * fontToUnitRatio; + var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"]) * fontToUnitRatio; + + //if float is set to right, move the image to the right border + //add space if margin is set + if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') { + imageX += renderer.settings.width - cn.width - additionalSpaceRight; + } else { + imageX += additionalSpaceLeft; + } + + renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height); + cached_image = undefined; + //if the float prop is specified we have to float the text around the image + if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') { + //add functiont to set back coordinates after image rendering + renderer.watchFunctions.push(function (diffX, thresholdY, diffWidth, el) { + //undo drawing box adaptions which were set by floating + if (renderer.y >= thresholdY) { + renderer.x += diffX; + renderer.settings.width += diffWidth; + return true; + } else if (el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x + el.width > renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width) { + renderer.x += diffX; + renderer.y = thresholdY; + renderer.settings.width += diffWidth; + return true; + } else { + return false; + } + }.bind(this, imagesCSS['float'] === 'left' ? -cn.width - additionalSpaceLeft - additionalSpaceRight : 0, renderer.y + cn.height + additionalSpaceTop + additionalSpaceBottom, cn.width)); + //reset floating by clear:both divs + //just set cursorY after the floating element + renderer.watchFunctions.push(function (yPositionAfterFloating, pages, el) { + if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) { + if (el.nodeType === 1 && GetCSS(el).clear === 'both') { + renderer.y = yPositionAfterFloating; + return true; + } else { + return false; + } + } else { + return true; + } + }.bind(this, renderer.y + cn.height, renderer.pdf.internal.getNumberOfPages())); + + //if floating is set we decrease the available width by the image width + renderer.settings.width -= cn.width + additionalSpaceLeft + additionalSpaceRight; + //if left just add the image width to the X coordinate + if (imagesCSS['float'] === 'left') { + renderer.x += cn.width + additionalSpaceLeft + additionalSpaceRight; + } + } else { + //if no floating is set, move the rendering cursor after the image height + renderer.y += cn.height + additionalSpaceTop + additionalSpaceBottom; + } + + /*** TABLE RENDERING ***/ + } else if (cn.nodeName === "TABLE") { + table2json = tableToJson(cn, renderer); + renderer.y += 10; + renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, { + autoSize: false, + printHeaders: elementHandlers.printHeaders, + margins: renderer.pdf.margins_doc, + css: GetCSS(cn) + }); + renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20; + } else if (cn.nodeName === "OL" || cn.nodeName === "UL") { + listCount = 1; + if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { + _DrillForContent(cn, renderer, elementHandlers); + } + renderer.y += 10; + } else if (cn.nodeName === "LI") { + var temp = renderer.x; + renderer.x += 20 / renderer.pdf.internal.scaleFactor; + renderer.y += 3; + if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { + _DrillForContent(cn, renderer, elementHandlers); + } + renderer.x = temp; + } else if (cn.nodeName === "BR") { + renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor; + renderer.addText("\u2028", clone(fragmentCSS)); + } else { + if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { + _DrillForContent(cn, renderer, elementHandlers); + } + } + } else if (cn.nodeType === 3) { + var value = cn.nodeValue; + if (cn.nodeValue && cn.parentNode.nodeName === "LI") { + if (cn.parentNode.parentNode.nodeName === "OL") { + value = listCount++ + '. ' + value; + } else { + var fontSize = fragmentCSS["font-size"]; + var offsetX = (3 - fontSize * 0.75) * renderer.pdf.internal.scaleFactor; + var offsetY = fontSize * 0.75 * renderer.pdf.internal.scaleFactor; + var radius = fontSize * 1.74 / renderer.pdf.internal.scaleFactor; + cb = function cb(x, y) { + this.pdf.circle(x + offsetX, y + offsetY, radius, 'FD'); + }; + } + } + // Only add the text if the text node is in the body element + // Add compatibility with IE11 + if (!!(cn.ownerDocument.body.compareDocumentPosition(cn) & 16)) { + renderer.addText(value, fragmentCSS); + } + } else if (typeof cn === "string") { + renderer.addText(cn, fragmentCSS); + } + } + i++; + } + elementHandlers.outY = renderer.y; + + if (isBlock) { + return renderer.setBlockBoundary(cb); + } + }; + images = {}; + loadImgs = function loadImgs(element, renderer, elementHandlers, cb) { + var imgs = element.getElementsByTagName('img'), + l = imgs.length, + found_images, + x = 0; + function done() { + renderer.pdf.internal.events.publish('imagesLoaded'); + cb(found_images); + } + function loadImage(url, width, height) { + if (!url) return; + var img = new Image(); + found_images = ++x; + img.crossOrigin = ''; + img.onerror = img.onload = function () { + if (img.complete) { + //to support data urls in images, set width and height + //as those values are not recognized automatically + if (img.src.indexOf('data:image/') === 0) { + img.width = width || img.width || 0; + img.height = height || img.height || 0; + } + //if valid image add to known images array + if (img.width + img.height) { + var hash = renderer.pdf.sHashCode(url) || url; + images[hash] = images[hash] || img; + } + } + if (! --x) { + done(); + } + }; + img.src = url; + } + while (l--) { + loadImage(imgs[l].getAttribute("src"), imgs[l].width, imgs[l].height); + }return x || done(); + }; + checkForFooter = function checkForFooter(elem, renderer, elementHandlers) { + //check if we can found a
    element + var footer = elem.getElementsByTagName("footer"); + if (footer.length > 0) { + + footer = footer[0]; + + //bad hack to get height of footer + //creat dummy out and check new y after fake rendering + var oldOut = renderer.pdf.internal.write; + var oldY = renderer.y; + renderer.pdf.internal.write = function () {}; + _DrillForContent(footer, renderer, elementHandlers); + var footerHeight = Math.ceil(renderer.y - oldY) + 5; + renderer.y = oldY; + renderer.pdf.internal.write = oldOut; + + //add 20% to prevent overlapping + renderer.pdf.margins_doc.bottom += footerHeight; + + //Create function render header on every page + var renderFooter = function renderFooter(pageInfo) { + var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1; + //set current y position to old margin + var oldPosition = renderer.y; + //render all child nodes of the header element + renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom; + renderer.pdf.margins_doc.bottom -= footerHeight; + + //check if we have to add page numbers + var spans = footer.getElementsByTagName('span'); + for (var i = 0; i < spans.length; ++i) { + //if we find some span element with class pageCounter, set the page + if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) { + spans[i].innerHTML = pageNumber; + } + //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages + if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) { + spans[i].innerHTML = '###jsPDFVarTotalPages###'; + } + } + + //render footer content + _DrillForContent(footer, renderer, elementHandlers); + //set bottom margin to previous height including the footer height + renderer.pdf.margins_doc.bottom += footerHeight; + //important for other plugins (e.g. table) to start rendering at correct position after header + renderer.y = oldPosition; + }; + + //check if footer contains totalPages which should be replace at the disoposal of the document + var spans = footer.getElementsByTagName('span'); + for (var i = 0; i < spans.length; ++i) { + if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) { + renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true); + } + } + + //register event to render footer on every new page + renderer.pdf.internal.events.subscribe('addPage', renderFooter, false); + //render footer on first page + renderFooter(); + + //prevent footer rendering + SkipNode['FOOTER'] = 1; + } + }; + process = function process(pdf, element, x, y, settings, callback) { + if (!element) return false; + if (typeof element !== "string" && !element.parentNode) element = '' + element.innerHTML; + if (typeof element === "string") { + element = function (element) { + var $frame, $hiddendiv, framename, visuallyhidden; + framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0); + visuallyhidden = "position: absolute !important;" + "clip: rect(1px 1px 1px 1px); /* IE6, IE7 */" + "clip: rect(1px, 1px, 1px, 1px);" + "padding:0 !important;" + "border:0 !important;" + "height: 1px !important;" + "width: 1px !important; " + "top:auto;" + "left:-100px;" + "overflow: hidden;"; + $hiddendiv = document.createElement('div'); + $hiddendiv.style.cssText = visuallyhidden; + $hiddendiv.innerHTML = "