From 5e7062295b92bb69f6c498ededf0479d57c06419 Mon Sep 17 00:00:00 2001
From: Martin Edenhofer
Date: Tue, 25 Apr 2017 11:04:41 +0200
Subject: [PATCH 01/31] Removed state and priority refs in seeds.rb.
---
...170403000001_fixed_admin_user_permission_920.rb | 4 ++--
db/seeds.rb | 14 ++++++--------
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/db/migrate/20170403000001_fixed_admin_user_permission_920.rb b/db/migrate/20170403000001_fixed_admin_user_permission_920.rb
index 61187f01c..970463353 100644
--- a/db/migrate/20170403000001_fixed_admin_user_permission_920.rb
+++ b/db/migrate/20170403000001_fixed_admin_user_permission_920.rb
@@ -159,7 +159,7 @@ class FixedAdminUserPermission920 < ActiveRecord::Migration
nulloption: true,
multiple: false,
null: false,
- default: Ticket::State.find_by(name: 'open').id,
+ default: Ticket::State.find_by(default_follow_up: true).id,
translate: true,
filter: Ticket::State.by_category(:viewable).pluck(:id),
},
@@ -249,7 +249,7 @@ class FixedAdminUserPermission920 < ActiveRecord::Migration
nulloption: false,
multiple: false,
null: false,
- default: Ticket::Priority.find_by(name: '2 normal').id,
+ default: Ticket::Priority.find_by(default_create: true).id,
translate: true,
},
editable: false,
diff --git a/db/seeds.rb b/db/seeds.rb
index 6b7546828..2f20b8227 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -3345,7 +3345,7 @@ Macro.create_if_not_exists(
name: 'Close & Tag as Spam',
perform: {
'ticket.state_id' => {
- value: Ticket::State.find_by(name: 'closed').id,
+ value: Ticket::State.by_category(:closed).first.id,
},
'ticket.tags' => {
operator: 'add',
@@ -3365,8 +3365,6 @@ ticket = Ticket.create(
group_id: Group.find_by(name: 'Users').id,
customer_id: User.find_by(login: 'nicole.braun@zammad.org').id,
title: 'Welcome to Zammad!',
- state_id: Ticket::State.find_by(name: 'new').id,
- priority_id: Ticket::Priority.find_by(name: '2 normal').id,
)
Ticket::Article.create(
ticket_id: ticket.id,
@@ -3935,7 +3933,7 @@ ObjectManager::Attribute.add(
nulloption: true,
multiple: false,
null: false,
- default: Ticket::State.find_by(name: 'open').id,
+ default: Ticket::State.find_by(default_follow_up: true).id,
translate: true,
filter: Ticket::State.by_category(:viewable).pluck(:id),
},
@@ -3953,7 +3951,7 @@ ObjectManager::Attribute.add(
nulloption: false,
null: true,
filter: Ticket::State.by_category(:viewable_customer_new).pluck(:id),
- default: Ticket::State.find_by(name: 'new').id,
+ default: Ticket::State.find_by(default_create: true).id,
},
},
edit: {
@@ -3966,7 +3964,7 @@ ObjectManager::Attribute.add(
nulloption: false,
null: true,
filter: Ticket::State.by_category(:viewable_customer_edit).pluck(:id),
- default: Ticket::State.find_by(name: 'open').id,
+ default: Ticket::State.find_by(default_follow_up: true).id,
},
},
},
@@ -4025,7 +4023,7 @@ ObjectManager::Attribute.add(
nulloption: false,
multiple: false,
null: false,
- default: Ticket::Priority.find_by(name: '2 normal').id,
+ default: Ticket::Priority.find_by(default_create: true).id,
translate: true,
},
editable: false,
@@ -5597,7 +5595,7 @@ Trigger.create_or_update(
},
'ticket.state_id' => {
'operator' => 'is not',
- 'value' => Ticket::State.lookup(name: 'closed').id,
+ 'value' => Ticket::State.by_category(:closed).first.id,
},
'article.type_id' => {
'operator' => 'is',
From 0fd75fa4827d7e1c893ec8fced18de022bdad82f Mon Sep 17 00:00:00 2001
From: Thorsten Eckel
Date: Wed, 26 Apr 2017 13:28:32 +0200
Subject: [PATCH 02/31] Moved seeds to own files and call them in a loop to
restructure them and make separate executions (for resetting purposes)
possible.
---
db/seeds.rb | 5767 +------------------------
db/seeds/channels.rb | 27 +
db/seeds/chats.rb | 8 +
db/seeds/community_user_resources.rb | 44 +
db/seeds/groups.rb | 8 +
db/seeds/karma_activities.rb | 66 +
db/seeds/links.rb | 6 +
db/seeds/macros.rb | 18 +
db/seeds/networks.rb | 100 +
db/seeds/object_manager_attributes.rb | 1667 +++++++
db/seeds/overviews.rb | 216 +
db/seeds/permissions.rb | 361 ++
db/seeds/report_profiles.rb | 7 +
db/seeds/roles.rb | 33 +
db/seeds/schedulers.rb | 167 +
db/seeds/settings.rb | 2798 ++++++++++++
db/seeds/signatures.rb | 14 +
db/seeds/ticket_article_senders.rb | 3 +
db/seeds/ticket_article_types.rb | 12 +
db/seeds/ticket_priorities.rb | 3 +
db/seeds/ticket_state_types.rb | 7 +
db/seeds/ticket_states.rb | 44 +
db/seeds/triggers.rb | 110 +
db/seeds/user_nr_1.rb | 12 +
24 files changed, 5745 insertions(+), 5753 deletions(-)
create mode 100644 db/seeds/channels.rb
create mode 100644 db/seeds/chats.rb
create mode 100644 db/seeds/community_user_resources.rb
create mode 100644 db/seeds/groups.rb
create mode 100644 db/seeds/karma_activities.rb
create mode 100644 db/seeds/links.rb
create mode 100644 db/seeds/macros.rb
create mode 100644 db/seeds/networks.rb
create mode 100644 db/seeds/object_manager_attributes.rb
create mode 100644 db/seeds/overviews.rb
create mode 100644 db/seeds/permissions.rb
create mode 100644 db/seeds/report_profiles.rb
create mode 100644 db/seeds/roles.rb
create mode 100644 db/seeds/schedulers.rb
create mode 100644 db/seeds/settings.rb
create mode 100644 db/seeds/signatures.rb
create mode 100644 db/seeds/ticket_article_senders.rb
create mode 100644 db/seeds/ticket_article_types.rb
create mode 100644 db/seeds/ticket_priorities.rb
create mode 100644 db/seeds/ticket_state_types.rb
create mode 100644 db/seeds/ticket_states.rb
create mode 100644 db/seeds/triggers.rb
create mode 100644 db/seeds/user_nr_1.rb
diff --git a/db/seeds.rb b/db/seeds.rb
index 2f20b8227..885aa4407 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -10,5759 +10,19 @@
# clear old caches to start from scratch
Cache.clear
-Setting.create_if_not_exists(
- title: 'Application secret',
- name: 'application_secret',
- area: 'Core',
- description: 'Defines the random application secret.',
- options: {},
- state: SecureRandom.hex(128),
- preferences: {
- permission: ['admin'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'System Init Done',
- name: 'system_init_done',
- area: 'Core',
- description: 'Defines if application is in init mode.',
- options: {},
- state: false,
- preferences: { online_service_disable: true },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'App Version',
- name: 'app_version',
- area: 'Core::WebApp',
- description: 'Only used internally to propagate current web app version to clients.',
- options: {},
- state: '',
- preferences: { online_service_disable: true },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Maintenance Mode',
- name: 'maintenance_mode',
- area: 'Core::WebApp',
- description: 'Enable or disable the maintenance mode of Zammad. If enabled, all non-administrators get logged out and only administrators can start a new session.',
- options: {},
- state: false,
- preferences: {
- permission: ['admin.maintenance'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Maintenance Login',
- name: 'maintenance_login',
- area: 'Core::WebApp',
- description: 'Put a message on the login page. To change it, click on the text area below and change it inline.',
- options: {},
- state: false,
- preferences: {
- permission: ['admin.maintenance'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Maintenance Login',
- name: 'maintenance_login_message',
- area: 'Core::WebApp',
- description: 'Message for login page.',
- options: {},
- state: 'Something about to share. Click here to change.',
- preferences: {
- permission: ['admin.maintenance'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Developer System',
- name: 'developer_mode',
- area: 'Core::Develop',
- description: 'Defines if application is in developer mode (useful for developer, all users have the same password, password reset will work without email delivery).',
- options: {},
- state: false,
- preferences: { online_service_disable: true },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Online Service',
- name: 'system_online_service',
- area: 'Core',
- description: 'Defines if application is used as online service.',
- options: {},
- state: false,
- preferences: { online_service_disable: true },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Product Name',
- name: 'product_name',
- area: 'System::Branding',
- description: 'Defines the name of the application, shown in the web interface, tabs and title bar of the web browser.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'product_name',
- tag: 'input',
- },
- ],
- },
- preferences: {
- render: true,
- prio: 1,
- placeholder: true,
- permission: ['admin.branding'],
- },
- state: 'Zammad Helpdesk',
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Logo',
- name: 'product_logo',
- area: 'System::Branding',
- description: 'Defines the logo of the application, shown in the web interface.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'product_logo',
- tag: 'input',
- },
- ],
- },
- preferences: {
- prio: 3,
- controller: 'SettingsAreaLogo',
- permission: ['admin.branding'],
- },
- state: 'logo.svg',
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Organization',
- name: 'organization',
- area: 'System::Branding',
- description: 'Will be shown in the app and is included in email footers.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'organization',
- tag: 'input',
- },
- ],
- },
- state: '',
- preferences: {
- prio: 2,
- placeholder: true,
- permission: ['admin.branding'],
- },
- frontend: true
-)
-Setting.create_or_update(
- title: 'Pretty Date',
- name: 'pretty_date_format',
- area: 'System::Branding',
- description: 'Defines pretty date format.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'pretty_date_format',
- tag: 'select',
- options: {
- 'relative': 'relative - e. g. "2 hours ago" or "2 days and 15 minutes ago"',
- 'absolute': 'absolute - e. g. "Monday 09:30" or "Tuesday 23. Feb 14:20"',
- },
- },
- ],
- },
- preferences: {
- render: true,
- prio: 10,
- permission: ['admin.branding'],
- },
- state: 'relative',
- frontend: true
-)
-options = {}
-(10..99).each { |item|
- options[item] = item
-}
-system_id = rand(10..99)
-Setting.create_if_not_exists(
- title: 'SystemID',
- name: 'system_id',
- area: 'System::Base',
- description: 'Defines the system identifier. Every ticket number contains this ID. This ensures that only tickets which belong to your system will be processed as follow-ups (useful when communicating between two instances of Zammad).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'system_id',
- tag: 'select',
- options: options,
- },
- ],
- },
- state: system_id,
- preferences: {
- online_service_disable: true,
- placeholder: true,
- authentication: true,
- permission: ['admin.system'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Fully Qualified Domain Name',
- name: 'fqdn',
- area: 'System::Base',
- description: 'Defines the fully qualified domain name of the system. This setting is used as a variable, #{setting.fqdn} which is found in all forms of messaging used by the application, to build links to the tickets within your system.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'fqdn',
- tag: 'input',
- },
- ],
- },
- state: 'zammad.example.com',
- preferences: {
- online_service_disable: true,
- placeholder: true,
- permission: ['admin.system'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Websocket port',
- name: 'websocket_port',
- area: 'System::WebSocket',
- description: 'Defines the port of the websocket server.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'websocket_port',
- tag: 'input',
- },
- ],
- },
- state: '6042',
- preferences: { online_service_disable: true },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'HTTP type',
- name: 'http_type',
- area: 'System::Base',
- description: 'Define the http protocol of your instance.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'http_type',
- tag: 'select',
- options: {
- 'https' => 'https',
- 'http' => 'http',
- },
- },
- ],
- },
- state: 'http',
- preferences: {
- online_service_disable: true,
- placeholder: true,
- permission: ['admin.system'],
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Storage Mechanism',
- name: 'storage_provider',
- area: 'System::Storage',
- description: '"Database" stores all attachments in the database (not recommended for storing large amounts of data). "Filesystem" stores the data in the filesystem. You can switch between the modules even on a system that is already in production without any loss of data.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'storage_provider',
- tag: 'select',
- tranlate: true,
- options: {
- 'DB' => 'Database',
- 'File' => 'Filesystem',
- },
- },
- ],
- },
- state: 'DB',
- preferences: {
- controller: 'SettingsAreaStorageProvider',
- online_service_disable: true,
- permission: ['admin.system'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Image Service',
- name: 'image_backend',
- area: 'System::Services',
- description: 'Defines the backend for user and organization image lookups.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'image_backend',
- tag: 'select',
- options: {
- '' => '-',
- 'Service::Image::Zammad' => 'Zammad Image Service',
- },
- },
- ],
- },
- state: 'Service::Image::Zammad',
- preferences: {
- prio: 1,
- permission: ['admin.system'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Geo IP Service',
- name: 'geo_ip_backend',
- area: 'System::Services',
- description: 'Defines the backend for geo IP lookups. Shows also location of an IP address if an IP address is shown.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'geo_ip_backend',
- tag: 'select',
- options: {
- '' => '-',
- 'Service::GeoIp::Zammad' => 'Zammad GeoIP Service',
- },
- },
- ],
- },
- state: 'Service::GeoIp::Zammad',
- preferences: {
- prio: 2,
- permission: ['admin.system'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Geo Location Service',
- name: 'geo_location_backend',
- area: 'System::Services',
- description: 'Defines the backend for geo location lookups to store geo locations for addresses.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'geo_location_backend',
- tag: 'select',
- options: {
- '' => '-',
- 'Service::GeoLocation::Gmaps' => 'Google Maps',
- },
- },
- ],
- },
- state: 'Service::GeoLocation::Gmaps',
- preferences: {
- prio: 3,
- permission: ['admin.system'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Geo Calendar Service',
- name: 'geo_calendar_backend',
- area: 'System::Services',
- description: 'Defines the backend for geo calendar lookups. Used for initial calendar succession.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'geo_calendar_backend',
- tag: 'select',
- options: {
- '' => '-',
- 'Service::GeoCalendar::Zammad' => 'Zammad GeoCalendar Service',
- },
- },
- ],
- },
- state: 'Service::GeoCalendar::Zammad',
- preferences: {
- prio: 2,
- permission: ['admin.system'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Proxy Settings',
- name: 'proxy',
- area: 'System::Network',
- description: 'Address of the proxy server for http and https resources.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'proxy',
- tag: 'input',
- placeholder: 'proxy.example.com:3128',
- },
- ],
- },
- state: '',
- preferences: {
- online_service_disable: true,
- controller: 'SettingsAreaProxy',
- prio: 1,
- permission: ['admin.system'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Proxy User',
- name: 'proxy_username',
- area: 'System::Network',
- description: 'Username for proxy connection.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'proxy_username',
- tag: 'input',
- },
- ],
- },
- state: '',
- preferences: {
- disabled: true,
- online_service_disable: true,
- prio: 2,
- permission: ['admin.system'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Proxy Password',
- name: 'proxy_password',
- area: 'System::Network',
- description: 'Password for proxy connection.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'proxy_passowrd',
- tag: 'input',
- },
- ],
- },
- state: '',
- preferences: {
- disabled: true,
- online_service_disable: true,
- prio: 3,
- permission: ['admin.system'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Send client stats',
- name: 'ui_send_client_stats',
- area: 'System::UI',
- description: 'Send client stats/error message to central server to improve the usability.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ui_send_client_stats',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- permission: ['admin.system'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Client storage',
- name: 'ui_client_storage',
- area: 'System::UI',
- description: 'Use client storage to cache data to enhance performance of application.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ui_client_storage',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 2,
- permission: ['admin.system'],
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Define default visibility of new a new article',
- name: 'ui_ticket_zoom_article_new_internal',
- area: 'UI::TicketZoom',
- description: 'Set default visibility of new a new article.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ui_ticket_zoom_article_new_internal',
- tag: 'boolean',
- translate: true,
- options: {
- true => 'internal',
- false => 'public',
- },
- },
- ],
- },
- state: true,
- preferences: {
- prio: 1,
- permission: ['admin.ui'],
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'New User Accounts',
- name: 'user_create_account',
- area: 'Security::Base',
- description: 'Enables users to create their own account via web interface.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'user_create_account',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- permission: ['admin.security'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Lost Password',
- name: 'user_lost_password',
- area: 'Security::Base',
- description: 'Activates lost password feature for users.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'user_lost_password',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- permission: ['admin.security'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_ldap',
- area: 'Security::Authentication',
- description: 'Enables user authentication via %s.',
- preferences: {
- title_i18n: ['LDAP'],
- description_i18n: ['LDAP'],
- permission: ['admin.security'],
- },
- state: {
- adapter: 'Auth::Ldap',
- host: 'localhost',
- port: 389,
- bind_dn: 'cn=Manager,dc=example,dc=org',
- bind_pw: 'example',
- uid: 'mail',
- base: 'dc=example,dc=org',
- always_filter: '',
- always_roles: %w(Admin Agent),
- always_groups: ['Users'],
- sync_params: {
- firstname: 'sn',
- lastname: 'givenName',
- email: 'mail',
- login: 'mail',
- },
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_twitter',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_twitter',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_twitter_credentials'],
- title_i18n: ['Twitter'],
- description_i18n: ['Twitter', 'Twitter Developer Site', 'https://dev.twitter.com/apps'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Twitter App Credentials',
- name: 'auth_twitter_credentials',
- area: 'Security::ThirdPartyAuthentication::Twitter',
- description: 'App credentials for Twitter.',
- options: {
- form: [
- {
- display: 'Twitter Key',
- null: true,
- name: 'key',
- tag: 'input',
- },
- {
- display: 'Twitter Secret',
- null: true,
- name: 'secret',
- tag: 'input',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_facebook',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_facebook',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_facebook_credentials'],
- title_i18n: ['Facebook'],
- description_i18n: ['Facebook', 'Facebook Developer Site', 'https://developers.facebook.com/apps/'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Facebook App Credentials',
- name: 'auth_facebook_credentials',
- area: 'Security::ThirdPartyAuthentication::Facebook',
- description: 'App credentials for Facebook.',
- options: {
- form: [
- {
- display: 'App ID',
- null: true,
- name: 'app_id',
- tag: 'input',
- },
- {
- display: 'App Secret',
- null: true,
- name: 'app_secret',
- tag: 'input',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_google_oauth2',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_google_oauth2',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_google_oauth2_credentials'],
- title_i18n: ['Google'],
- description_i18n: ['Google', 'Google API Console Site', 'https://console.developers.google.com/apis/credentials'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Google App Credentials',
- name: 'auth_google_oauth2_credentials',
- area: 'Security::ThirdPartyAuthentication::Google',
- description: 'Enables user authentication via Google.',
- options: {
- form: [
- {
- display: 'Client ID',
- null: true,
- name: 'client_id',
- tag: 'input',
- },
- {
- display: 'Client Secret',
- null: true,
- name: 'client_secret',
- tag: 'input',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_linkedin',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_linkedin',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_linkedin_credentials'],
- title_i18n: ['LinkedIn'],
- description_i18n: ['LinkedIn', 'Linkedin Developer Site', 'https://www.linkedin.com/developer/apps'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'LinkedIn App Credentials',
- name: 'auth_linkedin_credentials',
- area: 'Security::ThirdPartyAuthentication::Linkedin',
- description: 'Enables user authentication via LinkedIn.',
- options: {
- form: [
- {
- display: 'App ID',
- null: true,
- name: 'app_id',
- tag: 'input',
- },
- {
- display: 'App Secret',
- null: true,
- name: 'app_secret',
- tag: 'input',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_github',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_github',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_github_credentials'],
- title_i18n: ['Github'],
- description_i18n: ['Github', 'Github OAuth Applications', 'https://github.com/settings/applications'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Github App Credentials',
- name: 'auth_github_credentials',
- area: 'Security::ThirdPartyAuthentication::Github',
- description: 'Enables user authentication via Github.',
- options: {
- form: [
- {
- display: 'App ID',
- null: true,
- name: 'app_id',
- tag: 'input',
- },
- {
- display: 'App Secret',
- null: true,
- name: 'app_secret',
- tag: 'input',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_gitlab',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_gitlab',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_gitlab_credentials'],
- title_i18n: ['Gitlab'],
- description_i18n: ['Gitlab', 'Gitlab Applications', 'https://your-gitlab-host/admin/applications'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Gitlab App Credentials',
- name: 'auth_gitlab_credentials',
- area: 'Security::ThirdPartyAuthentication::Gitlab',
- description: 'Enables user authentication via Gitlab.',
- options: {
- form: [
- {
- display: 'App ID',
- null: true,
- name: 'app_id',
- tag: 'input',
- },
- {
- display: 'App Secret',
- null: true,
- name: 'app_secret',
- tag: 'input',
- },
- {
- display: 'Site',
- null: true,
- name: 'site',
- tag: 'input',
- placeholder: 'https://gitlab.YOURDOMAIN.com',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Authentication via %s',
- name: 'auth_oauth2',
- area: 'Security::ThirdPartyAuthentication',
- description: 'Enables user authentication via generic OAuth2. Register your app first.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'auth_oauth2',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- controller: 'SettingsAreaSwitch',
- sub: ['auth_oauth2_credentials'],
- title_i18n: ['Generic OAuth2'],
- permission: ['admin.security'],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Generic OAuth2 App Credentials',
- name: 'auth_oauth2_credentials',
- area: 'Security::ThirdPartyAuthentication::GenericOAuth',
- description: 'Enables user authentication via generic OAuth2.',
- options: {
- form: [
- {
- display: 'Name',
- null: true,
- name: 'name',
- tag: 'input',
- placeholder: 'Some Provider Name',
- },
- {
- display: 'App ID',
- null: true,
- name: 'app_id',
- tag: 'input',
- },
- {
- display: 'App Secret',
- null: true,
- name: 'app_secret',
- tag: 'input',
- },
- {
- display: 'Site',
- null: true,
- name: 'site',
- tag: 'input',
- placeholder: 'https://gitlab.YOURDOMAIN.com',
- },
- {
- display: 'authorize_url',
- null: true,
- name: 'authorize_url',
- tag: 'input',
- placeholder: '/oauth/authorize',
- },
- {
- display: 'token_url',
- null: true,
- name: 'token_url',
- tag: 'input',
- placeholder: '/oauth/token',
- },
- ],
- },
- state: {},
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Minimum length',
- name: 'password_min_size',
- area: 'Security::Password',
- description: 'Password needs to have at least a minimal number of characters.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'password_min_size',
- tag: 'select',
- options: {
- 4 => ' 4',
- 5 => ' 5',
- 6 => ' 6',
- 7 => ' 7',
- 8 => ' 8',
- 9 => ' 9',
- 10 => '10',
- 11 => '11',
- 12 => '12',
- 13 => '13',
- 14 => '14',
- 15 => '15',
- 16 => '16',
- 17 => '17',
- 18 => '18',
- 19 => '19',
- 20 => '20',
- },
- },
- ],
- },
- state: 6,
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: '2 lower and 2 upper characters',
- name: 'password_min_2_lower_2_upper_characters',
- area: 'Security::Password',
- description: 'Password needs to contain 2 lower and 2 upper characters.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'password_min_2_lower_2_upper_characters',
- tag: 'select',
- options: {
- 1 => 'yes',
- 0 => 'no',
- },
- },
- ],
- },
- state: 0,
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Digit required',
- name: 'password_need_digit',
- area: 'Security::Password',
- description: 'Password needs to contain at least one digit.',
- options: {
- form: [
- {
- display: 'Needed',
- null: true,
- name: 'password_need_digit',
- tag: 'select',
- options: {
- 1 => 'yes',
- 0 => 'no',
- },
- },
- ],
- },
- state: 1,
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Maximum failed logins',
- name: 'password_max_login_failed',
- area: 'Security::Password',
- description: 'Number of failed logins after account will be deactivated.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'password_max_login_failed',
- tag: 'select',
- options: {
- 4 => ' 4',
- 5 => ' 5',
- 6 => ' 6',
- 7 => ' 7',
- 8 => ' 8',
- 9 => ' 9',
- 10 => '10',
- 11 => '11',
- 13 => '13',
- 14 => '14',
- 15 => '15',
- 16 => '16',
- 17 => '17',
- 18 => '18',
- 19 => '19',
- 20 => '20',
- },
- },
- ],
- },
- state: 10,
- preferences: {
- permission: ['admin.security'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Ticket Hook',
- name: 'ticket_hook',
- area: 'Ticket::Base',
- description: 'The identifier for a ticket, e. g. Ticket#, Call#, MyTicket#. The default is Ticket#.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'ticket_hook',
- tag: 'input',
- },
- ],
- },
- preferences: {
- render: true,
- placeholder: true,
- authentication: true,
- permission: ['admin.ticket'],
- },
- state: 'Ticket#',
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Ticket Hook Divider',
- name: 'ticket_hook_divider',
- area: 'Ticket::Base::Shadow',
- description: 'The divider between TicketHook and ticket number. E. g. \': \'.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ticket_hook_divider',
- tag: 'input',
- },
- ],
- },
- state: '',
- preferences: {
- permission: ['admin.ticket'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Ticket Hook Position',
- name: 'ticket_hook_position',
- area: 'Ticket::Base',
- description: "The format of the subject.
-* **Right** means **Some Subject [Ticket#12345]**
-* **Left** means **[Ticket#12345] Some Subject**
-* **None** means **Some Subject** (without ticket number). In the last case you should enable *postmaster_follow_up_search_in* to recognize follow-ups based on email headers and/or body.",
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ticket_hook_position',
- tag: 'select',
- translate: true,
- options: {
- 'left' => 'left',
- 'right' => 'right',
- 'none' => 'none',
- },
- },
- ],
- },
- state: 'right',
- preferences: {
- controller: 'SettingsAreaTicketHookPosition',
- permission: ['admin.ticket'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Ticket Number Format',
- name: 'ticket_number',
- area: 'Ticket::Number',
- description: "Selects the ticket number generator module.
-* **Increment** increments the ticket number, the SystemID and the counter are used with SystemID.Counter format (e.g. 1010138, 1010139).
-* With **Date** the ticket numbers will be generated by the current date, the SystemID and the counter. The format looks like Year.Month.Day.SystemID.counter (e.g. 201206231010138, 201206231010139).",
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ticket_number',
- tag: 'select',
- translate: true,
- options: {
- 'Ticket::Number::Increment' => 'Increment (SystemID.Counter)',
- 'Ticket::Number::Date' => 'Date (Year.Month.Day.SystemID.Counter)',
- },
- },
- ],
- },
- state: 'Ticket::Number::Increment',
- preferences: {
- settings_included: %w(ticket_number_increment ticket_number_date),
- controller: 'SettingsAreaTicketNumber',
- permission: ['admin.ticket'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Ticket Number Increment',
- name: 'ticket_number_increment',
- area: 'Ticket::Number',
- description: '-',
- options: {
- form: [
- {
- display: 'Checksum',
- null: true,
- name: 'checksum',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- {
- display: 'Min. size of number',
- null: true,
- name: 'min_size',
- tag: 'select',
- options: {
- 1 => ' 1',
- 2 => ' 2',
- 3 => ' 3',
- 4 => ' 4',
- 5 => ' 5',
- 6 => ' 6',
- 7 => ' 7',
- 8 => ' 8',
- 9 => ' 9',
- 10 => '10',
- 11 => '11',
- 12 => '12',
- 13 => '13',
- 14 => '14',
- 15 => '15',
- 16 => '16',
- 17 => '17',
- 18 => '18',
- 19 => '19',
- 20 => '20',
- },
- },
- ],
- },
- state: {
- checksum: false,
- min_size: 5,
- },
- preferences: {
- permission: ['admin.ticket'],
- hidden: true,
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Ticket Number Increment Date',
- name: 'ticket_number_date',
- area: 'Ticket::Number',
- description: '-',
- options: {
- form: [
- {
- display: 'Checksum',
- null: true,
- name: 'checksum',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: {
- checksum: false
- },
- preferences: {
- permission: ['admin.ticket'],
- hidden: true,
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Enable Ticket creation',
- name: 'customer_ticket_create',
- area: 'CustomerWeb::Base',
- description: 'Defines if a customer can create tickets via the web interface.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'customer_ticket_create',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- authentication: true,
- permission: ['admin.channel_web'],
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Group selection for Ticket creation',
- name: 'customer_ticket_create_group_ids',
- area: 'CustomerWeb::Base',
- description: 'Defines groups for which a customer can create tickets via web interface. "-" means all groups are available.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'group_ids',
- tag: 'select',
- multiple: true,
- nulloption: true,
- relation: 'Group',
- },
- ],
- },
- state: '',
- preferences: {
- authentication: true,
- permission: ['admin.channel_web'],
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Enable Ticket creation',
- name: 'form_ticket_create',
- area: 'Form::Base',
- description: 'Defines if tickets can be created via web form.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'form_ticket_create',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- permission: ['admin.channel_formular'],
- },
- frontend: false,
-)
-
-Setting.create_if_not_exists(
- title: 'Ticket Subject Size',
- name: 'ticket_subject_size',
- area: 'Email::Base',
- description: 'Max. length of the subject in an email reply.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'ticket_subject_size',
- tag: 'input',
- },
- ],
- },
- state: '110',
- preferences: {
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Ticket Subject Reply',
- name: 'ticket_subject_re',
- area: 'Email::Base',
- description: 'The text at the beginning of the subject in an email reply, e. g. RE, AW, or AS.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ticket_subject_re',
- tag: 'input',
- },
- ],
- },
- state: 'RE',
- preferences: {
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Sender Format',
- name: 'ticket_define_email_from',
- area: 'Email::Base',
- description: 'Defines how the From field of emails (sent from answers and email tickets) should look like.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ticket_define_email_from',
- tag: 'select',
- options: {
- SystemAddressName: 'System Address Display Name',
- AgentNameSystemAddressName: 'Agent Name + FromSeparator + System Address Display Name',
- },
- },
- ],
- },
- state: 'AgentNameSystemAddressName',
- preferences: {
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Sender Format Separator',
- name: 'ticket_define_email_from_separator',
- area: 'Email::Base',
- description: 'Defines the separator between the agent\'s real name and the given group email address.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'ticket_define_email_from_separator',
- tag: 'input',
- },
- ],
- },
- state: 'via',
- preferences: {
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Maximum Email Size',
- name: 'postmaster_max_size',
- area: 'Email::Base',
- description: 'Maximum size in MB of emails.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'postmaster_max_size',
- tag: 'select',
- options: {
- 1 => ' 1',
- 2 => ' 2',
- 3 => ' 3',
- 4 => ' 4',
- 5 => ' 5',
- 6 => ' 6',
- 7 => ' 7',
- 8 => ' 8',
- 9 => ' 9',
- 10 => ' 10',
- 15 => ' 15',
- 20 => ' 20',
- 25 => ' 25',
- 30 => ' 30',
- 35 => ' 35',
- 40 => ' 40',
- 45 => ' 45',
- 50 => ' 50',
- 60 => ' 60',
- 70 => ' 70',
- 80 => ' 80',
- 90 => ' 90',
- 100 => '100',
- 125 => '125',
- 150 => '150',
- },
- },
- ],
- },
- state: 10,
- preferences: {
- online_service_disable: true,
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Additional follow-up detection',
- name: 'postmaster_follow_up_search_in',
- area: 'Email::Base',
- description: 'By default the follow-up check is done via the subject of an email. With this setting you can add more fields for which the follow-up check will be executed.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'postmaster_follow_up_search_in',
- tag: 'checkbox',
- options: {
- 'references' => 'References - Search for follow up also in In-Reply-To or References headers.',
- 'body' => 'Body - Search for follow up also in mail body.',
- 'attachment' => 'Attachment - Search for follow up also in attachments.',
- },
- },
- ],
- },
- state: [],
- preferences: {
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Notification Sender',
- name: 'notification_sender',
- area: 'Email::Base',
- description: 'Defines the sender of email notifications.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'notification_sender',
- tag: 'input',
- },
- ],
- },
- state: 'Notification Master ',
- preferences: {
- online_service_disable: true,
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Block Notifications',
- name: 'send_no_auto_response_reg_exp',
- area: 'Email::Base',
- description: 'If this regex matches, no notification will be sent by the sender.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'send_no_auto_response_reg_exp',
- tag: 'input',
- },
- ],
- },
- state: '(mailer-daemon|postmaster|abuse|root|noreply|noreply.+?|no-reply|no-reply.+?)@.+?\..+?',
- preferences: {
- online_service_disable: true,
- permission: ['admin.channel_email'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'API Token Access',
- name: 'api_token_access',
- area: 'API::Base',
- description: 'Enable REST API using tokens (not username/email address and password). Each user needs to create its own access tokens in user profile.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'api_token_access',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- permission: ['admin.api'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'API Password Access',
- name: 'api_password_access',
- area: 'API::Base',
- description: 'Enable REST API access using the username/email address and password for the authentication user.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'api_password_access',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- permission: ['admin.api'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Monitoring Token',
- name: 'monitoring_token',
- area: 'HealthCheck::Base',
- description: 'Token for monitoring.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'monitoring_token',
- tag: 'input',
- },
- ],
- },
- state: SecureRandom.urlsafe_base64(40),
- preferences: {
- permission: ['admin.monitoring'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Enable Chat',
- name: 'chat',
- area: 'Chat::Base',
- description: 'Enable/disable online chat.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'chat',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- trigger: ['menu:render', 'chat:rerender'],
- permission: ['admin.channel_chat'],
- },
- state: false,
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Agent idle timeout',
- name: 'chat_agent_idle_timeout',
- area: 'Chat::Extended',
- description: 'Idle timeout in seconds until agent is set offline automatically.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'chat_agent_idle_timeout',
- tag: 'input',
- },
- ],
- },
- state: '120',
- preferences: {
- permission: ['admin.channel_chat'],
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Defines searchable models.',
- name: 'models_searchable',
- area: 'Models::Base',
- description: 'Defines the searchable models.',
- options: {},
- state: [],
- preferences: {
- authentication: true,
- },
- frontend: true,
-)
-
-Setting.create_if_not_exists(
- title: 'Default Screen',
- name: 'default_controller',
- area: 'Core',
- description: 'Defines the default screen.',
- options: {},
- state: '#dashboard',
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Elasticsearch Endpoint URL',
- name: 'es_url',
- area: 'SearchIndex::Elasticsearch',
- description: 'Defines endpoint of Elasticsearch.',
- state: '',
- preferences: { online_service_disable: true },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Elasticsearch Endpoint User',
- name: 'es_user',
- area: 'SearchIndex::Elasticsearch',
- description: 'Defines HTTP basic auth user of Elasticsearch.',
- state: '',
- preferences: { online_service_disable: true },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Elasticsearch Endpoint Password',
- name: 'es_password',
- area: 'SearchIndex::Elasticsearch',
- description: 'Defines HTTP basic auth password of Elasticsearch.',
- state: '',
- preferences: { online_service_disable: true },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Elasticsearch Endpoint Index',
- name: 'es_index',
- area: 'SearchIndex::Elasticsearch',
- description: 'Defines Elasticsearch index name.',
- state: 'zammad',
- preferences: { online_service_disable: true },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Elasticsearch Attachment Extensions',
- name: 'es_attachment_ignore',
- area: 'SearchIndex::Elasticsearch',
- description: 'Defines attachment extensions which will be ignored by Elasticsearch.',
- state: [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe', '.box', '.mbox' ],
- preferences: { online_service_disable: true },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Elasticsearch Attachment Size',
- name: 'es_attachment_max_size_in_mb',
- area: 'SearchIndex::Elasticsearch',
- description: 'Define max. attachment size for Elasticsearch.',
- state: 50,
- preferences: { online_service_disable: true },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Import Mode',
- name: 'import_mode',
- area: 'Import::Base',
- description: 'Puts Zammad into import mode (disables some triggers).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'import_mode',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Import Backend',
- name: 'import_backend',
- area: 'Import::Base::Internal',
- description: 'Set backend which is being used for import.',
- options: {},
- state: '',
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'Ignore Escalation/SLA Information',
- name: 'import_ignore_sla',
- area: 'Import::Base',
- description: 'Ignore escalation/SLA information for import.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'import_ignore_sla',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Import Endpoint',
- name: 'import_otrs_endpoint',
- area: 'Import::OTRS',
- description: 'Defines OTRS endpoint to import users, tickets, states and articles.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'import_otrs_endpoint',
- tag: 'input',
- },
- ],
- },
- state: 'http://otrs_host/otrs',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Import Key',
- name: 'import_otrs_endpoint_key',
- area: 'Import::OTRS',
- description: 'Defines OTRS endpoint authentication key.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'import_otrs_endpoint_key',
- tag: 'input',
- },
- ],
- },
- state: '',
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Import User for HTTP basic authentication',
- name: 'import_otrs_user',
- area: 'Import::OTRS',
- description: 'Defines HTTP basic authentication user (only if OTRS is protected via HTTP basic auth).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'import_otrs_user',
- tag: 'input',
- },
- ],
- },
- state: '',
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Import Password for http basic authentication',
- name: 'import_otrs_password',
- area: 'Import::OTRS',
- description: 'Defines http basic authentication password (only if OTRS is protected via http basic auth).',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'import_otrs_password',
- tag: 'input',
- },
- ],
- },
- state: '',
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Import Endpoint',
- name: 'import_zendesk_endpoint',
- area: 'Import::Zendesk',
- description: 'Defines Zendesk endpoint to import users, ticket, states and articles.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'import_zendesk_endpoint',
- tag: 'input',
- },
- ],
- },
- state: 'https://yours.zendesk.com/api/v2',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Import Key for requesting the Zendesk API',
- name: 'import_zendesk_endpoint_key',
- area: 'Import::Zendesk',
- description: 'Defines Zendesk endpoint authentication key.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'import_zendesk_endpoint_key',
- tag: 'input',
- },
- ],
- },
- state: '',
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Import User for requesting the Zendesk API',
- name: 'import_zendesk_endpoint_username',
- area: 'Import::Zendesk',
- description: 'Defines Zendesk endpoint authentication user.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'import_zendesk_endpoint_username',
- tag: 'input',
- },
- ],
- },
- state: '',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Import Backends',
- name: 'import_backends',
- area: 'Import',
- description: 'A list of active import backends that get scheduled automatically.',
- options: {},
- state: ['Import::Ldap'],
- preferences: {
- permission: ['admin'],
- },
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Time Accounting',
- name: 'time_accounting',
- area: 'Web::Base',
- description: 'Enable time accounting.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'time_accounting',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- authentication: true,
- permission: ['admin.time_accounting'],
- },
- state: false,
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Time Accounting Selector',
- name: 'time_accounting_selector',
- area: 'Web::Base',
- description: 'Enable time accounting for these tickets.',
- options: {
- form: [
- {},
- ],
- },
- preferences: {
- authentication: true,
- permission: ['admin.time_accounting'],
- },
- state: {},
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'New Tags',
- name: 'tag_new',
- area: 'Web::Base',
- description: 'Allow users to create new tags.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'tag_new',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- preferences: {
- authentication: true,
- permission: ['admin.tag'],
- },
- state: true,
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Default calendar tickets subscriptions',
- name: 'defaults_calendar_subscriptions_tickets',
- area: 'Defaults::CalendarSubscriptions',
- description: 'Defines the default calendar tickets subscription settings.',
- options: {},
- state: {
- escalation: {
- own: true,
- not_assigned: false,
- },
- new_open: {
- own: true,
- not_assigned: false,
- },
- pending: {
- own: true,
- not_assigned: false,
- }
- },
- preferences: {
- authentication: true,
- },
- frontend: true
-)
-
-Setting.create_if_not_exists(
- title: 'Defines translator identifier.',
- name: 'translator_key',
- area: 'i18n::translator_key',
- description: 'Defines the translator identifier for contributions.',
- options: {},
- state: '',
- frontend: false
-)
-
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0010_postmaster_filter_trusted',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to remove X-Zammad headers from not trusted sources.',
- options: {},
- state: 'Channel::Filter::Trusted',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0012_postmaster_filter_sender_is_system_address',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to check if email has been created by Zammad itself and will set the article sender.',
- options: {},
- state: 'Channel::Filter::SenderIsSystemAddress',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0014_postmaster_filter_own_notification_loop_detection',
- area: 'Postmaster::PreFilter',
- description: 'Define postmaster filter to check if email is a own created notification email, then ignore it to prevent email loops.',
- options: {},
- state: 'Channel::Filter::OwnNotificationLoopDetection',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0015_postmaster_filter_identify_sender',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to identify sender user.',
- options: {},
- state: 'Channel::Filter::IdentifySender',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0020_postmaster_filter_auto_response_check',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to identify auto responses to prevent auto replies from Zammad.',
- options: {},
- state: 'Channel::Filter::AutoResponseCheck',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0030_postmaster_filter_out_of_office_check',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to identify out-of-office emails for follow-up detection and keeping current ticket state.',
- options: {},
- state: 'Channel::Filter::OutOfOfficeCheck',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0100_postmaster_filter_follow_up_check',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to identify follow-ups (based on admin settings).',
- options: {},
- state: 'Channel::Filter::FollowUpCheck',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0200_postmaster_filter_follow_up_possible_check',
- area: 'Postmaster::PreFilter',
- description: 'Define postmaster filter to check if follow ups get created (based on admin settings).',
- options: {},
- state: 'Channel::Filter::FollowUpPossibleCheck',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '0900_postmaster_filter_bounce_check',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to identify postmaster bounced - to handle it as follow-up of the original ticket.',
- options: {},
- state: 'Channel::Filter::BounceCheck',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '1000_postmaster_filter_database_check',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter for filters managed via admin interface.',
- options: {},
- state: 'Channel::Filter::Database',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '5000_postmaster_filter_icinga',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to manage Icinga (http://www.icinga.org) emails.',
- options: {},
- state: 'Channel::Filter::Icinga',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines postmaster filter.',
- name: '5100_postmaster_filter_nagios',
- area: 'Postmaster::PreFilter',
- description: 'Defines postmaster filter to manage Nagios (http://www.nagios.org) emails.',
- options: {},
- state: 'Channel::Filter::Nagios',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Icinga integration',
- name: 'icinga_integration',
- area: 'Integration::Switch',
- description: 'Defines if Icinga (http://www.icinga.org) is enabled or not.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'icinga_integration',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Sender',
- name: 'icinga_sender',
- area: 'Integration::Icinga',
- description: 'Defines the sender email address of Icinga emails.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'icinga_sender',
- tag: 'input',
- placeholder: 'icinga@monitoring.example.com',
- },
- ],
- },
- state: 'icinga@monitoring.example.com',
- preferences: {
- prio: 2,
- permission: ['admin.integration'],
- },
- frontend: false,
-)
-Setting.create_if_not_exists(
- title: 'Auto close',
- name: 'icinga_auto_close',
- area: 'Integration::Icinga',
- description: 'Defines if tickets should be closed if service is recovered.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'icinga_auto_close',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- prio: 3,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Auto close state',
- name: 'icinga_auto_close_state_id',
- area: 'Integration::Icinga',
- description: 'Defines the state of auto closed tickets.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'icinga_auto_close_state_id',
- tag: 'select',
- relation: 'TicketState',
- },
- ],
- },
- state: 4,
- preferences: {
- prio: 4,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Nagios integration',
- name: 'nagios_integration',
- area: 'Integration::Switch',
- description: 'Defines if Nagios (http://www.nagios.org) is enabled or not.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'nagios_integration',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Sender',
- name: 'nagios_sender',
- area: 'Integration::Nagios',
- description: 'Defines the sender email address of Nagios emails.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'nagios_sender',
- tag: 'input',
- placeholder: 'nagios@monitoring.example.com',
- },
- ],
- },
- state: 'nagios@monitoring.example.com',
- preferences: {
- prio: 2,
- permission: ['admin.integration'],
- },
- frontend: false,
-)
-Setting.create_if_not_exists(
- title: 'Auto close',
- name: 'nagios_auto_close',
- area: 'Integration::Nagios',
- description: 'Defines if tickets should be closed if service is recovered.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'nagios_auto_close',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: true,
- preferences: {
- prio: 3,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Auto close state',
- name: 'nagios_auto_close_state_id',
- area: 'Integration::Nagios',
- description: 'Defines the state of auto closed tickets.',
- options: {
- form: [
- {
- display: '',
- null: false,
- name: 'nagios_auto_close_state_id',
- tag: 'select',
- relation: 'TicketState',
- },
- ],
- },
- state: 4,
- preferences: {
- prio: 4,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'LDAP integration',
- name: 'ldap_integration',
- area: 'Integration::Switch',
- description: 'Defines if LDAP is enabled or not.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'ldap_integration',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- authentication: true,
- permission: ['admin.integration'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'LDAP config',
- name: 'ldap_config',
- area: 'Integration::LDAP',
- description: 'Defines the LDAP config.',
- options: {},
- state: {},
- preferences: {
- prio: 2,
- permission: ['admin.integration'],
- },
- frontend: false,
-)
-Setting.create_if_not_exists(
- title: 'Defines sync transaction backend.',
- name: '0100_trigger',
- area: 'Transaction::Backend::Sync',
- description: 'Defines the transaction backend to execute triggers.',
- options: {},
- state: 'Transaction::Trigger',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines transaction backend.',
- name: '0100_notification',
- area: 'Transaction::Backend::Async',
- description: 'Defines the transaction backend to send agent notifications.',
- options: {},
- state: 'Transaction::Notification',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines transaction backend.',
- name: '1000_signature_detection',
- area: 'Transaction::Backend::Async',
- description: 'Defines the transaction backend to detect customer signatures in emails.',
- options: {},
- state: 'Transaction::SignatureDetection',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines transaction backend.',
- name: '6000_slack_webhook',
- area: 'Transaction::Backend::Async',
- description: 'Defines the transaction backend which posts messages to Slack (http://www.slack.com).',
- options: {},
- state: 'Transaction::Slack',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Slack integration',
- name: 'slack_integration',
- area: 'Integration::Switch',
- description: 'Defines if Slack (http://www.slack.org) is enabled or not.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'slack_integration',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Slack config',
- name: 'slack_config',
- area: 'Integration::Slack',
- description: 'Defines the slack config.',
- options: {},
- state: {
- items: []
- },
- preferences: {
- prio: 2,
- permission: ['admin.integration'],
- },
- frontend: false,
-)
-Setting.create_if_not_exists(
- title: 'sipgate.io integration',
- name: 'sipgate_integration',
- area: 'Integration::Switch',
- description: 'Defines if sipgate.io (http://www.sipgate.io) is enabled or not.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'sipgate_integration',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- trigger: ['menu:render', 'cti:reload'],
- authentication: true,
- permission: ['admin.integration'],
- },
- frontend: true
-)
-Setting.create_if_not_exists(
- title: 'sipgate.io config',
- name: 'sipgate_config',
- area: 'Integration::Sipgate',
- description: 'Defines the sipgate.io config.',
- options: {},
- state: {},
- preferences: {
- prio: 2,
- permission: ['admin.integration'],
- },
- frontend: false,
-)
-Setting.create_if_not_exists(
- title: 'Clearbit integration',
- name: 'clearbit_integration',
- area: 'Integration::Switch',
- description: 'Defines if Clearbit (http://www.clearbit.com) is enabled or not.',
- options: {
- form: [
- {
- display: '',
- null: true,
- name: 'clearbit_integration',
- tag: 'boolean',
- options: {
- true => 'yes',
- false => 'no',
- },
- },
- ],
- },
- state: false,
- preferences: {
- prio: 1,
- permission: ['admin.integration'],
- },
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Clearbit config',
- name: 'clearbit_config',
- area: 'Integration::Clearbit',
- description: 'Defines the Clearbit config.',
- options: {},
- state: {},
- frontend: false,
- preferences: {
- prio: 2,
- permission: ['admin.integration'],
- },
-)
-Setting.create_if_not_exists(
- title: 'Defines transaction backend.',
- name: '9000_clearbit_enrichment',
- area: 'Transaction::Backend::Async',
- description: 'Defines the transaction backend which will enrich customer and organization information from Clearbit (http://www.clearbit.com).',
- options: {},
- state: 'Transaction::ClearbitEnrichment',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines transaction backend.',
- name: '9100_cti_caller_id_detection',
- area: 'Transaction::Backend::Async',
- description: 'Defines the transaction backend which detects caller IDs in objects and store them for CTI lookups.',
- options: {},
- state: 'Transaction::CtiCallerIdDetection',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines transaction backend.',
- name: '9200_karma',
- area: 'Transaction::Backend::Async',
- description: 'Defines the transaction backend which creates the karma score.',
- options: {},
- state: 'Transaction::Karma',
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Defines karma levels.',
- name: 'karma_levels',
- area: 'Core::Karma',
- description: 'Defines the karma levels.',
- options: {},
- state: [
- {
- name: 'Beginner',
- start: 0,
- end: 499,
- },
- {
- name: 'Newbie',
- start: 500,
- end: 1999,
- },
- {
- name: 'Intermediate',
- start: 2000,
- end: 4999,
- },
- {
- name: 'Professional',
- start: 5000,
- end: 6999,
- },
- {
- name: 'Expert',
- start: 7000,
- end: 8999,
- },
- {
- name: 'Master',
- start: 9000,
- end: 18_999,
- },
- {
- name: 'Evangelist',
- start: 19_000,
- end: 45_999,
- },
- {
- name: 'Hero',
- start: 50_000,
- end: nil,
- },
- ],
- frontend: false
-)
-Setting.create_if_not_exists(
- title: 'Set limit of agents',
- name: 'system_agent_limit',
- area: 'Core::Online',
- description: 'Defines the limit of the agents.',
- options: {},
- state: false,
- preferences: { online_service_disable: true },
- frontend: false
-)
-
-signature = Signature.create_if_not_exists(
- id: 1,
- name: 'default',
- body: '
- #{user.firstname} #{user.lastname}
-
---
- Super Support - Waterford Business Park
- 5201 Blue Lagoon Drive - 8th Floor & 9th Floor - Miami, 33126 USA
- Email: hot@example.com - Web: http://www.example.com/
---'.text2html,
- updated_by_id: 1,
- created_by_id: 1
-)
-
-Role.create_if_not_exists(
- id: 1,
- name: 'Admin',
- note: 'To configure your system.',
- preferences: {
- not: ['Customer'],
- },
- default_at_signup: false,
- updated_by_id: 1,
- created_by_id: 1
-)
-Role.create_if_not_exists(
- id: 2,
- name: 'Agent',
- note: 'To work on Tickets.',
- default_at_signup: false,
- preferences: {
- not: ['Customer'],
- },
- updated_by_id: 1,
- created_by_id: 1
-)
-Role.create_if_not_exists(
- id: 3,
- name: 'Customer',
- note: 'People who create Tickets ask for help.',
- preferences: {
- not: %w(Agent Admin),
- },
- default_at_signup: true,
- updated_by_id: 1,
- created_by_id: 1
-)
-
-Permission.create_if_not_exists(
- name: 'admin',
- note: 'Admin Interface',
- preferences: {},
-)
-Permission.create_if_not_exists(
- name: 'admin.user',
- note: 'Manage %s',
- preferences: {
- translations: ['Users']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.group',
- note: 'Manage %s',
- preferences: {
- translations: ['Groups']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.role',
- note: 'Manage %s',
- preferences: {
- translations: ['Roles']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.organization',
- note: 'Manage %s',
- preferences: {
- translations: ['Organizations']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.overview',
- note: 'Manage %s',
- preferences: {
- translations: ['Overviews']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.text_module',
- note: 'Manage %s',
- preferences: {
- translations: ['Text Modules']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.macro',
- note: 'Manage %s',
- preferences: {
- translations: ['Macros']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.tag',
- note: 'Manage %s',
- preferences: {
- translations: ['Tags']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.calendar',
- note: 'Manage %s',
- preferences: {
- translations: ['Calendar']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.sla',
- note: 'Manage %s',
- preferences: {
- translations: ['SLA']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.scheduler',
- note: 'Manage %s',
- preferences: {
- translations: ['Scheduler']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.report_profile',
- note: 'Manage %s',
- preferences: {
- translations: ['Report Profiles']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_web',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Web']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_formular',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Formular']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_email',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Email']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_twitter',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Twitter']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_facebook',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Facebook']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_telegram',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Telegram']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.channel_chat',
- note: 'Manage %s',
- preferences: {
- translations: ['Channel - Chat']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.branding',
- note: 'Manage %s',
- preferences: {
- translations: ['Branding']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.setting_system',
- note: 'Manage %s Settings',
- preferences: {
- translations: ['System']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.security',
- note: 'Manage %s Settings',
- preferences: {
- translations: ['Security']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.ticket',
- note: 'Manage %s Settings',
- preferences: {
- translations: ['Ticket']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.package',
- note: 'Manage %s',
- preferences: {
- translations: ['Packages']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.integration',
- note: 'Manage %s',
- preferences: {
- translations: ['Integrations']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.api',
- note: 'Manage %s',
- preferences: {
- translations: ['API']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.object',
- note: 'Manage %s',
- preferences: {
- translations: ['Objects']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.translation',
- note: 'Manage %s',
- preferences: {
- translations: ['Translations']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.monitoring',
- note: 'Manage %s',
- preferences: {
- translations: ['Monitoring']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.maintenance',
- note: 'Manage %s',
- preferences: {
- translations: ['Maintenance']
- },
-)
-Permission.create_if_not_exists(
- name: 'admin.session',
- note: 'Manage %s',
- preferences: {
- translations: ['Sessions']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences',
- note: 'User Preferences',
- preferences: {},
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.password',
- note: 'Change %s',
- preferences: {
- translations: ['Password']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.notifications',
- note: 'Manage %s',
- preferences: {
- translations: ['Notifications'],
- required: ['ticket.agent'],
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.access_token',
- note: 'Manage %s',
- preferences: {
- translations: ['Token Access']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.language',
- note: 'Change %s',
- preferences: {
- translations: ['Language']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.linked_accounts',
- note: 'Manage %s',
- preferences: {
- translations: ['Linked Accounts']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.device',
- note: 'Manage %s',
- preferences: {
- translations: ['Devices']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.avatar',
- note: 'Manage %s',
- preferences: {
- translations: ['Avatar']
- },
-)
-Permission.create_if_not_exists(
- name: 'user_preferences.calendar',
- note: 'Access to %s',
- preferences: {
- translations: ['Calendars'],
- required: ['ticket.agent'],
- },
-)
-
-Permission.create_if_not_exists(
- name: 'report',
- note: 'Report Interface',
- preferences: {},
-)
-Permission.create_if_not_exists(
- name: 'ticket',
- note: 'Ticket Interface',
- preferences: {
- disabled: true
- },
-)
-Permission.create_if_not_exists(
- name: 'ticket.agent',
- note: 'Access to Agent Tickets based on Group Access',
- preferences: {
- not: ['ticket.customer'],
- plugin: ['groups']
- },
-)
-Permission.create_if_not_exists(
- name: 'ticket.customer',
- note: 'Access to Customer Tickets based on current_user.id and current_user.organization_id',
- preferences: {
- not: ['ticket.agent'],
- },
-)
-Permission.create_if_not_exists(
- name: 'chat',
- note: 'Access to %s',
- preferences: {
- translations: ['Chat']
- },
-)
-Permission.create_if_not_exists(
- name: 'chat.agent',
- note: 'Access to %s',
- preferences: {
- translations: ['Chat'],
- not: ['chat.customer'],
- },
-)
-Permission.create_if_not_exists(
- name: 'cti',
- note: 'CTI',
- preferences: {
- disabled: true
- },
-)
-Permission.create_if_not_exists(
- name: 'cti.agent',
- note: 'Access to %s',
- preferences: {
- translations: ['CTI'],
- not: ['cti.customer'],
- },
-)
-
-admin = Role.find_by(name: 'Admin')
-admin.permission_grant('user_preferences')
-admin.permission_grant('admin')
-admin.permission_grant('report')
-
-agent = Role.find_by(name: 'Agent')
-agent.permission_grant('user_preferences')
-agent.permission_grant('ticket.agent')
-agent.permission_grant('chat.agent')
-agent.permission_grant('cti.agent')
-
-customer = Role.find_by(name: 'Customer')
-customer.permission_grant('user_preferences.password')
-customer.permission_grant('user_preferences.language')
-customer.permission_grant('user_preferences.linked_accounts')
-customer.permission_grant('user_preferences.avatar')
-customer.permission_grant('ticket.customer')
-
-Group.create_if_not_exists(
- id: 1,
- name: 'Users',
- signature_id: signature.id,
- note: 'Standard Group/Pool for Tickets.',
- updated_by_id: 1,
- created_by_id: 1
-)
-
-user = User.create_if_not_exists(
- id: 1,
- login: '-',
- firstname: '-',
- lastname: '',
- email: '',
- active: false,
- updated_by_id: 1,
- created_by_id: 1
-)
-
-UserInfo.current_user_id = 1
-roles = Role.find_by(name: 'Customer')
-organizations = Organization.all
-groups = Group.all
-org_community = Organization.create_if_not_exists(
- id: 1,
- name: 'Zammad Foundation',
-)
-user_community = User.create_or_update(
- id: 2,
- login: 'nicole.braun@zammad.org',
- firstname: 'Nicole',
- lastname: 'Braun',
- email: 'nicole.braun@zammad.org',
- password: '',
- active: true,
- roles: [roles],
- organization_id: org_community.id,
-)
-
-Link::Type.create_if_not_exists(id: 1, name: 'normal')
-Link::Object.create_if_not_exists(id: 1, name: 'Ticket')
-Link::Object.create_if_not_exists(id: 2, name: 'Announcement')
-Link::Object.create_if_not_exists(id: 3, name: 'Question/Answer')
-Link::Object.create_if_not_exists(id: 4, name: 'Idea')
-Link::Object.create_if_not_exists(id: 5, name: 'Bug')
-
-Ticket::StateType.create_if_not_exists(id: 1, name: 'new')
-Ticket::StateType.create_if_not_exists(id: 2, name: 'open')
-Ticket::StateType.create_if_not_exists(id: 3, name: 'pending reminder')
-Ticket::StateType.create_if_not_exists(id: 4, name: 'pending action')
-Ticket::StateType.create_if_not_exists(id: 5, name: 'closed')
-Ticket::StateType.create_if_not_exists(id: 6, name: 'merged')
-Ticket::StateType.create_if_not_exists(id: 7, name: 'removed')
-
-Ticket::State.create_if_not_exists(
- id: 1,
- name: 'new',
- state_type_id: Ticket::StateType.find_by(name: 'new').id,
- default_create: true,
-)
-Ticket::State.create_if_not_exists(
- id: 2,
- name: 'open',
- state_type_id: Ticket::StateType.find_by(name: 'open').id,
- default_follow_up: true,
-)
-Ticket::State.create_if_not_exists(
- id: 3,
- name: 'pending reminder',
- state_type_id: Ticket::StateType.find_by(name: 'pending reminder').id,
- ignore_escalation: true,
-)
-Ticket::State.create_if_not_exists(
- id: 4,
- name: 'closed',
- state_type_id: Ticket::StateType.find_by(name: 'closed').id,
- ignore_escalation: true,
-)
-Ticket::State.create_if_not_exists(
- id: 5,
- name: 'merged',
- state_type_id: Ticket::StateType.find_by(name: 'merged').id,
- ignore_escalation: true,
-)
-Ticket::State.create_if_not_exists(
- id: 6,
- name: 'removed',
- state_type_id: Ticket::StateType.find_by(name: 'removed').id,
- active: false,
- ignore_escalation: true,
-)
-Ticket::State.create_if_not_exists(
- id: 7,
- name: 'pending close',
- state_type_id: Ticket::StateType.find_by(name: 'pending action').id,
- next_state_id: Ticket::State.find_by(name: 'closed').id,
- ignore_escalation: true,
-)
-
-Ticket::Priority.create_if_not_exists(id: 1, name: '1 low')
-Ticket::Priority.create_if_not_exists(id: 2, name: '2 normal', default_create: true)
-Ticket::Priority.create_if_not_exists(id: 3, name: '3 high')
-
-Ticket::Article::Type.create_if_not_exists(id: 1, name: 'email', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 2, name: 'sms', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 3, name: 'chat', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 4, name: 'fax', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 5, name: 'phone', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 6, name: 'twitter status', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 7, name: 'twitter direct-message', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 8, name: 'facebook feed post', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 9, name: 'facebook feed comment', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 10, name: 'note', communication: false)
-Ticket::Article::Type.create_if_not_exists(id: 11, name: 'web', communication: true)
-Ticket::Article::Type.create_if_not_exists(id: 12, name: 'telegram personal-message', communication: true)
-
-Ticket::Article::Sender.create_if_not_exists(id: 1, name: 'Agent')
-Ticket::Article::Sender.create_if_not_exists(id: 2, name: 'Customer')
-Ticket::Article::Sender.create_if_not_exists(id: 3, name: 'System')
-
-Macro.create_if_not_exists(
- name: 'Close & Tag as Spam',
- perform: {
- 'ticket.state_id' => {
- value: Ticket::State.by_category(:closed).first.id,
- },
- 'ticket.tags' => {
- operator: 'add',
- value: 'spam',
- },
- 'ticket.owner_id' => {
- pre_condition: 'current_user.id',
- value: '',
- },
- },
- note: 'example macro',
- active: true,
-)
-
-UserInfo.current_user_id = user_community.id
-ticket = Ticket.create(
- group_id: Group.find_by(name: 'Users').id,
- customer_id: User.find_by(login: 'nicole.braun@zammad.org').id,
- title: 'Welcome to Zammad!',
-)
-Ticket::Article.create(
- ticket_id: ticket.id,
- type_id: Ticket::Article::Type.find_by(name: 'phone').id,
- sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
- from: 'Zammad Feedback ',
- body: 'Welcome!
-
-Thank you for choosing Zammad.
-
-You will find updates and patches at https://zammad.org/. Online
-documentation is available at https://zammad.org/documentation. Get
-involved (discussions, contributing, ...) at https://zammad.org/participate.
-
-Regards,
-
-Your Zammad Team
-',
- internal: false,
-)
-
-UserInfo.current_user_id = 1
-overview_role = Role.find_by(name: 'Agent')
-Overview.create_if_not_exists(
- name: 'My assigned Tickets',
- link: 'my_assigned',
- prio: 1000,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:open).pluck(:id),
- },
- 'ticket.owner_id' => {
- operator: 'is',
- pre_condition: 'current_user.id',
- },
- },
- order: {
- by: 'created_at',
- direction: 'ASC',
- },
- view: {
- d: %w(title customer group created_at),
- s: %w(title customer group created_at),
- m: %w(number title customer group created_at),
- view_mode_default: 's',
- },
-)
-
-Overview.create_if_not_exists(
- name: 'Unassigned & Open',
- link: 'all_unassigned',
- prio: 1010,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:work_on_all).pluck(:id),
- },
- 'ticket.owner_id' => {
- operator: 'is',
- pre_condition: 'not_set',
- },
- },
- order: {
- by: 'created_at',
- direction: 'ASC',
- },
- view: {
- d: %w(title customer group created_at),
- s: %w(title customer group created_at),
- m: %w(number title customer group created_at),
- view_mode_default: 's',
- },
-)
-
-Overview.create_if_not_exists(
- name: 'My pending reached Tickets',
- link: 'my_pending_reached',
- prio: 1020,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:pending_reminder).pluck(:id),
- },
- 'ticket.owner_id' => {
- operator: 'is',
- pre_condition: 'current_user.id',
- },
- 'ticket.pending_time' => {
- operator: 'within next (relative)',
- value: 0,
- range: 'minute',
- },
- },
- order: {
- by: 'created_at',
- direction: 'ASC',
- },
- view: {
- d: %w(title customer group created_at),
- s: %w(title customer group created_at),
- m: %w(number title customer group created_at),
- view_mode_default: 's',
- },
-)
-
-Overview.create_if_not_exists(
- name: 'Open',
- link: 'all_open',
- prio: 1030,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:work_on_all).pluck(:id),
- },
- },
- order: {
- by: 'created_at',
- direction: 'ASC',
- },
- view: {
- d: %w(title customer group state owner created_at),
- s: %w(title customer group state owner created_at),
- m: %w(number title customer group state owner created_at),
- view_mode_default: 's',
- },
-)
-
-Overview.create_if_not_exists(
- name: 'Pending reached',
- link: 'all_pending_reached',
- prio: 1040,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:pending_reminder).pluck(:id),
- },
- 'ticket.pending_time' => {
- operator: 'within next (relative)',
- value: 0,
- range: 'minute',
- },
- },
- order: {
- by: 'created_at',
- direction: 'ASC',
- },
- view: {
- d: %w(title customer group owner created_at),
- s: %w(title customer group owner created_at),
- m: %w(number title customer group owner created_at),
- view_mode_default: 's',
- },
-)
-
-Overview.create_if_not_exists(
- name: 'Escalated',
- link: 'all_escalated',
- prio: 1050,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.escalation_at' => {
- operator: 'within next (relative)',
- value: '10',
- range: 'minute',
- },
- },
- order: {
- by: 'escalation_at',
- direction: 'ASC',
- },
- view: {
- d: %w(title customer group owner escalation_at),
- s: %w(title customer group owner escalation_at),
- m: %w(number title customer group owner escalation_at),
- view_mode_default: 's',
- },
-)
-
-overview_role = Role.find_by(name: 'Customer')
-Overview.create_if_not_exists(
- name: 'My Tickets',
- link: 'my_tickets',
- prio: 1100,
- role_ids: [overview_role.id],
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:viewable).pluck(:id),
- },
- 'ticket.customer_id' => {
- operator: 'is',
- pre_condition: 'current_user.id',
- },
- },
- order: {
- by: 'created_at',
- direction: 'DESC',
- },
- view: {
- d: %w(title customer state created_at),
- s: %w(number title state created_at),
- m: %w(number title state created_at),
- view_mode_default: 's',
- },
-)
-Overview.create_if_not_exists(
- name: 'My Organization Tickets',
- link: 'my_organization_tickets',
- prio: 1200,
- role_ids: [overview_role.id],
- organization_shared: true,
- condition: {
- 'ticket.state_id' => {
- operator: 'is',
- value: Ticket::State.by_category(:viewable).pluck(:id),
- },
- 'ticket.organization_id' => {
- operator: 'is',
- pre_condition: 'current_user.organization_id',
- },
- },
- order: {
- by: 'created_at',
- direction: 'DESC',
- },
- view: {
- d: %w(title customer state created_at),
- s: %w(number title customer state created_at),
- m: %w(number title customer state created_at),
- view_mode_default: 's',
- },
-)
-
-Channel.create_if_not_exists(
- area: 'Email::Notification',
- options: {
- outbound: {
- adapter: 'smtp',
- options: {
- host: 'host.example.com',
- user: '',
- password: '',
- ssl: true,
- },
- },
- },
- group_id: 1,
- preferences: { online_service_disable: true },
- active: false,
-)
-Channel.create_if_not_exists(
- area: 'Email::Notification',
- options: {
- outbound: {
- adapter: 'sendmail',
- },
- },
- preferences: { online_service_disable: true },
- active: true,
-)
-
-Report::Profile.create_if_not_exists(
- name: '-all-',
- condition: {},
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-
-chat = Chat.create_if_not_exists(
- name: 'default',
- max_queue: 5,
- note: '',
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-
-network = Network.create_if_not_exists(
- id: 1,
- name: 'base',
-)
-
-Network::Category::Type.create_if_not_exists(
- id: 1,
- name: 'Announcement',
-)
-Network::Category::Type.create_if_not_exists(
- id: 2,
- name: 'Idea',
-)
-Network::Category::Type.create_if_not_exists(
- id: 3,
- name: 'Question',
-)
-Network::Category::Type.create_if_not_exists(
- id: 4,
- name: 'Bug Report',
-)
-
-Network::Privacy.create_if_not_exists(
- id: 1,
- name: 'logged in',
- key: 'loggedIn',
-)
-Network::Privacy.create_if_not_exists(
- id: 2,
- name: 'logged in and moderator',
- key: 'loggedInModerator',
-)
-Network::Category.create_if_not_exists(
- id: 1,
- name: 'Announcements',
- network_id: network.id,
- network_category_type_id: Network::Category::Type.find_by(name: 'Announcement').id,
- network_privacy_id: Network::Privacy.find_by(name: 'logged in and moderator').id,
- allow_comments: true,
-)
-Network::Category.create_if_not_exists(
- id: 2,
- name: 'Questions',
- network_id: network.id,
- allow_comments: true,
- network_category_type_id: Network::Category::Type.find_by(name: 'Question').id,
- network_privacy_id: Network::Privacy.find_by(name: 'logged in').id,
-)
-Network::Category.create_if_not_exists(
- id: 3,
- name: 'Ideas',
- network_id: network.id,
- network_category_type_id: Network::Category::Type.find_by(name: 'Idea').id,
- network_privacy_id: Network::Privacy.find_by(name: 'logged in').id,
- allow_comments: true,
-)
-Network::Category.create_if_not_exists(
- id: 4,
- name: 'Bug Reports',
- network_id: network.id,
- network_category_type_id: Network::Category::Type.find_by(name: 'Bug Report').id,
- network_privacy_id: Network::Privacy.find_by(name: 'logged in').id,
- allow_comments: true,
-)
-item = Network::Item.create(
- title: 'Example Announcement',
- body: 'Some announcement....',
- network_category_id: Network::Category.find_by(name: 'Announcements').id,
-)
-Network::Item::Comment.create(
- network_item_id: item.id,
- body: 'Some comment....',
-)
-item = Network::Item.create(
- title: 'Example Question?',
- body: 'Some questions....',
- network_category_id: Network::Category.find_by(name: 'Questions').id,
-)
-Network::Item::Comment.create(
- network_item_id: item.id,
- body: 'Some comment....',
-)
-item = Network::Item.create(
- title: 'Example Idea',
- body: 'Some idea....',
- network_category_id: Network::Category.find_by(name: 'Ideas').id,
-)
-Network::Item::Comment.create(
- network_item_id: item.id,
- body: 'Some comment....',
-)
-item = Network::Item.create(
- title: 'Example Bug Report',
- body: 'Some bug....',
- network_category_id: Network::Category.find_by(name: 'Bug Reports').id,
-)
-Network::Item::Comment.create(
- network_item_id: item.id,
- body: 'Some comment....',
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'title',
- display: 'Title',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 200,
- null: false,
- translate: false,
- },
- editable: false,
- active: true,
- screens: {
- create_top: {
- '-all-' => {
- null: false,
- },
- },
- edit: {},
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 15,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'customer_id',
- display: 'Customer',
- data_type: 'user_autocompletion',
- data_option: {
- relation: 'User',
- autocapitalize: false,
- multiple: false,
- guess: true,
- null: false,
- limit: 200,
- placeholder: 'Enter Person or Organization/Company',
- minLengt: 2,
- translate: false,
- permission: ['ticket.agent'],
- },
- editable: false,
- active: true,
- screens: {
- create_top: {
- '-all-' => {
- null: false,
- },
- },
- edit: {},
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 10,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'type',
- display: 'Type',
- data_type: 'select',
- data_option: {
- default: '',
- options: {
- 'Incident' => 'Incident',
- 'Problem' => 'Problem',
- 'Request for Change' => 'Request for Change',
- },
- nulloption: true,
- multiple: false,
- null: true,
- translate: true,
- },
- editable: true,
- active: false,
- screens: {
- create_middle: {
- '-all-' => {
- null: false,
- item_class: 'column',
- },
- },
- edit: {
- 'ticket.agent' => {
- null: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 20,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'group_id',
- display: 'Group',
- data_type: 'select',
- data_option: {
- default: '',
- relation: 'Group',
- relation_condition: { access: 'rw' },
- nulloption: true,
- multiple: false,
- null: false,
- translate: false,
- only_shown_if_selectable: true,
- permission: ['ticket.agent', 'ticket.customer'],
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {
- '-all-' => {
- null: false,
- item_class: 'column',
- },
- },
- edit: {
- 'ticket.agent' => {
- null: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 25,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'owner_id',
- display: 'Owner',
- data_type: 'select',
- data_option: {
- default: '',
- relation: 'User',
- relation_condition: { roles: 'Agent' },
- nulloption: true,
- multiple: false,
- null: true,
- translate: false,
- permission: ['ticket.agent'],
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {
- '-all-' => {
- null: true,
- item_class: 'column',
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 30,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'state_id',
- display: 'State',
- data_type: 'select',
- data_option: {
- relation: 'TicketState',
- nulloption: true,
- multiple: false,
- null: false,
- default: Ticket::State.find_by(default_follow_up: true).id,
- translate: true,
- filter: Ticket::State.by_category(:viewable).pluck(:id),
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {
- 'ticket.agent' => {
- null: false,
- item_class: 'column',
- filter: Ticket::State.by_category(:viewable_agent_new).pluck(:id),
- },
- 'ticket.customer' => {
- item_class: 'column',
- nulloption: false,
- null: true,
- filter: Ticket::State.by_category(:viewable_customer_new).pluck(:id),
- default: Ticket::State.find_by(default_create: true).id,
- },
- },
- edit: {
- 'ticket.agent' => {
- nulloption: false,
- null: false,
- filter: Ticket::State.by_category(:viewable_agent_edit).pluck(:id),
- },
- 'ticket.customer' => {
- nulloption: false,
- null: true,
- filter: Ticket::State.by_category(:viewable_customer_edit).pluck(:id),
- default: Ticket::State.find_by(default_follow_up: true).id,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 40,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'pending_time',
- display: 'Pending till',
- data_type: 'datetime',
- data_option: {
- future: true,
- past: false,
- diff: 24,
- null: true,
- translate: true,
- required_if: {
- state_id: Ticket::State.by_category(:pending).pluck(:id),
- },
- shown_if: {
- state_id: Ticket::State.by_category(:pending).pluck(:id),
- },
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {
- '-all-' => {
- null: false,
- item_class: 'column',
- },
- },
- edit: {
- '-all-' => {
- null: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 41,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'priority_id',
- display: 'Priority',
- data_type: 'select',
- data_option: {
- relation: 'TicketPriority',
- nulloption: false,
- multiple: false,
- null: false,
- default: Ticket::Priority.find_by(default_create: true).id,
- translate: true,
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {
- 'ticket.agent' => {
- null: false,
- item_class: 'column',
- },
- },
- edit: {
- 'ticket.agent' => {
- null: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 80,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Ticket',
- name: 'tags',
- display: 'Tags',
- data_type: 'tag',
- data_option: {
- type: 'text',
- null: true,
- translate: false,
- },
- editable: false,
- active: true,
- screens: {
- create_bottom: {
- 'ticket.agent' => {
- null: true,
- },
- },
- edit: {},
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 900,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'TicketArticle',
- name: 'type_id',
- display: 'Type',
- data_type: 'select',
- data_option: {
- relation: 'TicketArticleType',
- nulloption: false,
- multiple: false,
- null: false,
- default: Ticket::Article::Type.lookup(name: 'note').id,
- translate: true,
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {},
- edit: {
- 'ticket.agent' => {
- null: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 100,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'TicketArticle',
- name: 'internal',
- display: 'Visibility',
- data_type: 'select',
- data_option: {
- options: { true: 'internal', false: 'public' },
- nulloption: false,
- multiple: false,
- null: true,
- default: false,
- translate: true,
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {},
- edit: {
- 'ticket.agent' => {
- null: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 200,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'TicketArticle',
- name: 'to',
- display: 'To',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 1000,
- null: true,
- },
- editable: false,
- active: true,
- screens: {
- create_middle: {},
- edit: {
- 'ticket.agent' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 300,
-)
-ObjectManager::Attribute.add(
- force: true,
- object: 'TicketArticle',
- name: 'cc',
- display: 'Cc',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 1000,
- null: true,
- },
- editable: false,
- active: true,
- screens: {
- create_top: {},
- create_middle: {},
- edit: {
- 'ticket.agent' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 400,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'TicketArticle',
- name: 'body',
- display: 'Text',
- data_type: 'richtext',
- data_option: {
- type: 'richtext',
- maxlength: 20_000,
- upload: true,
- rows: 8,
- null: true,
- },
- editable: false,
- active: true,
- screens: {
- create_top: {
- '-all-' => {
- null: false,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 600,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'login',
- display: 'Login',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 100,
- null: true,
- autocapitalize: false,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {},
- view: {
- '-all-' => {
- shown: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 100,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'firstname',
- display: 'Firstname',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 150,
- null: false,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {
- '-all-' => {
- null: false,
- },
- },
- invite_agent: {
- '-all-' => {
- null: false,
- },
- },
- invite_customer: {
- '-all-' => {
- null: false,
- },
- },
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 200,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'lastname',
- display: 'Lastname',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 150,
- null: false,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {
- '-all-' => {
- null: false,
- },
- },
- invite_agent: {
- '-all-' => {
- null: false,
- },
- },
- invite_customer: {
- '-all-' => {
- null: false,
- },
- },
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 300,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'email',
- display: 'Email',
- data_type: 'input',
- data_option: {
- type: 'email',
- maxlength: 150,
- null: false,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {
- '-all-' => {
- null: false,
- },
- },
- invite_agent: {
- '-all-' => {
- null: false,
- },
- },
- invite_customer: {
- '-all-' => {
- null: false,
- },
- },
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 400,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'web',
- display: 'Web',
- data_type: 'input',
- data_option: {
- type: 'url',
- maxlength: 250,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 500,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'phone',
- display: 'Phone',
- data_type: 'input',
- data_option: {
- type: 'tel',
- maxlength: 100,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 600,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'mobile',
- display: 'Mobile',
- data_type: 'input',
- data_option: {
- type: 'tel',
- maxlength: 100,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 700,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'fax',
- display: 'Fax',
- data_type: 'input',
- data_option: {
- type: 'tel',
- maxlength: 100,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 800,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'organization_id',
- display: 'Organization',
- data_type: 'autocompletion_ajax',
- data_option: {
- multiple: false,
- nulloption: true,
- null: true,
- relation: 'Organization',
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 900,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'department',
- display: 'Department',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 200,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: true,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1000,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'street',
- display: 'Street',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 100,
- null: true,
- },
- editable: true,
- active: false,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1100,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'zip',
- display: 'Zip',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 100,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: true,
- active: false,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1200,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'city',
- display: 'City',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 100,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: true,
- active: false,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1300,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'address',
- display: 'Address',
- data_type: 'textarea',
- data_option: {
- type: 'text',
- maxlength: 500,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: true,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1350,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'password',
- display: 'Password',
- data_type: 'input',
- data_option: {
- type: 'password',
- maxlength: 100,
- null: true,
- autocomplete: 'new-password',
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- signup: {
- '-all-' => {
- null: false,
- },
- },
- invite_agent: {},
- invite_customer: {},
- edit: {
- 'admin.user' => {
- null: true,
- },
- },
- view: {}
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1400,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'vip',
- display: 'VIP',
- data_type: 'boolean',
- data_option: {
- null: true,
- default: false,
- item_class: 'formGroup--halfSize',
- options: {
- false: 'no',
- true: 'yes',
- },
- translate: true,
- permission: ['admin.user', 'ticket.agent'],
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1490,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'note',
- display: 'Note',
- data_type: 'richtext',
- data_option: {
- type: 'text',
- maxlength: 250,
- null: true,
- note: 'Notes are visible to agents only, never to customers.',
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1500,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'role_ids',
- display: 'Permissions',
- data_type: 'user_permission',
- data_option: {
- null: false,
- item_class: 'checkbox',
- permission: ['admin.user'],
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {
- '-all-' => {
- null: false,
- default: [Role.lookup(name: 'Agent').id],
- },
- },
- invite_customer: {},
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1600,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'User',
- name: 'active',
- display: 'Active',
- data_type: 'active',
- data_option: {
- null: true,
- default: true,
- permission: ['admin.user', 'ticket.agent'],
- },
- editable: false,
- active: true,
- screens: {
- signup: {},
- invite_agent: {},
- invite_customer: {},
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1800,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Organization',
- name: 'name',
- display: 'Name',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 150,
- null: false,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 200,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Organization',
- name: 'shared',
- display: 'Shared organization',
- data_type: 'boolean',
- data_option: {
- null: true,
- default: true,
- note: 'Customers in the organization can view each other items.',
- item_class: 'formGroup--halfSize',
- options: {
- true: 'yes',
- false: 'no',
- },
- translate: true,
- permission: ['admin.organization'],
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1400,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Organization',
- name: 'domain_assignment',
- display: 'Domain based assignment',
- data_type: 'boolean',
- data_option: {
- null: true,
- default: false,
- note: 'Assign Users based on users domain.',
- item_class: 'formGroup--halfSize',
- options: {
- true: 'yes',
- false: 'no',
- },
- translate: true,
- permission: ['admin.organization'],
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1410,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Organization',
- name: 'domain',
- display: 'Domain',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 150,
- null: true,
- item_class: 'formGroup--halfSize',
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1420,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Organization',
- name: 'note',
- display: 'Note',
- data_type: 'richtext',
- data_option: {
- type: 'text',
- maxlength: 250,
- null: true,
- note: 'Notes are visible to agents only, never to customers.',
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1500,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Organization',
- name: 'active',
- display: 'Active',
- data_type: 'active',
- data_option: {
- null: true,
- default: true,
- permission: ['admin.organization'],
- },
- editable: false,
- active: true,
- screens: {
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1800,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'name',
- display: 'Name',
- data_type: 'input',
- data_option: {
- type: 'text',
- maxlength: 150,
- null: false,
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: false,
- },
- },
- edit: {
- '-all-' => {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 200,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'assignment_timeout',
- display: 'Assignment Timeout',
- data_type: 'integer',
- data_option: {
- maxlength: 150,
- null: true,
- note: 'Assignment timeout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.',
- min: 0,
- max: 999_999,
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 300,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'follow_up_possible',
- display: 'Follow up possible',
- data_type: 'select',
- data_option: {
- default: 'yes',
- options: {
- yes: 'yes',
- new_ticket: 'do not reopen Ticket but create new Ticket'
- },
- null: false,
- note: 'Follow up for closed ticket possible or not.',
- translate: true
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 400,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'follow_up_assignment',
- display: 'Assign Follow Ups',
- data_type: 'select',
- data_option: {
- default: 'yes',
- options: {
- true: 'yes',
- false: 'no',
- },
- null: false,
- note: 'Assign follow up to latest agent again.',
- translate: true
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 500,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'email_address_id',
- display: 'Email',
- data_type: 'select',
- data_option: {
- default: '',
- multiple: false,
- null: true,
- relation: 'EmailAddress',
- nulloption: true,
- do_not_log: true,
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 600,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'signature_id',
- display: 'Signature',
- data_type: 'select',
- data_option: {
- default: '',
- multiple: false,
- null: true,
- relation: 'Signature',
- nulloption: true,
- do_not_log: true,
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 600,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'note',
- display: 'Note',
- data_type: 'richtext',
- data_option: {
- type: 'text',
- maxlength: 250,
- null: true,
- note: 'Notes are visible to agents only, never to customers.',
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-' => {
- null: true,
- },
- },
- view: {
- '-all-' => {
- shown: true,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1500,
-)
-
-ObjectManager::Attribute.add(
- force: true,
- object: 'Group',
- name: 'active',
- display: 'Active',
- data_type: 'active',
- data_option: {
- null: true,
- default: true,
- permission: ['admin.group'],
- },
- editable: false,
- active: true,
- screens: {
- create: {
- '-all-' => {
- null: true,
- },
- },
- edit: {
- '-all-': {
- null: false,
- },
- },
- view: {
- '-all-' => {
- shown: false,
- },
- },
- },
- to_create: false,
- to_migrate: false,
- to_delete: false,
- position: 1800,
-)
-
-Scheduler.create_if_not_exists(
- name: 'Process pending tickets',
- method: 'Ticket.process_pending',
- period: 15.minutes,
- prio: 1,
- active: true,
-)
-Scheduler.create_if_not_exists(
- name: 'Process escalation tickets',
- method: 'Ticket.process_escalation',
- period: 5.minutes,
- prio: 1,
- active: true,
-)
-Scheduler.create_if_not_exists(
- name: 'Import OTRS diff load',
- method: 'Import::OTRS.diff_worker',
- period: 3.minutes,
- prio: 1,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Check Channels',
- method: 'Channel.fetch',
- period: 30.seconds,
- prio: 1,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Check streams for Channel',
- method: 'Channel.stream',
- period: 60.seconds,
- prio: 1,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Generate Session data',
- method: 'Sessions.jobs',
- period: 60.seconds,
- prio: 1,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Execute jobs',
- method: 'Job.run',
- period: 5.minutes,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Cleanup expired sessions',
- method: 'SessionHelper.cleanup_expired',
- period: 60 * 60 * 12,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Delete old activity stream entries.',
- method: 'ActivityStream.cleanup',
- period: 1.day,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Delete old entries.',
- method: 'RecentView.cleanup',
- period: 1.day,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Delete old online notification entries.',
- method: 'OnlineNotification.cleanup',
- period: 2.hours,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Delete old token entries.',
- method: 'Token.cleanup',
- period: 30.days,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Closed chat sessions where participients are offline.',
- method: 'Chat.cleanup_close',
- period: 15.minutes,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Cleanup closed sessions.',
- method: 'Chat.cleanup',
- period: 5.days,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Sync calendars with ical feeds.',
- method: 'Calendar.sync',
- period: 1.day,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Generate user based stats.',
- method: 'Stats.generate',
- period: 11.minutes,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_or_update(
- name: 'Delete old stats store entries.',
- method: 'StatsStore.cleanup',
- period: 31.days,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Cleanup HttpLog',
- method: 'HttpLog.cleanup',
- period: 1.day,
- prio: 2,
- active: true,
- updated_by_id: 1,
- created_by_id: 1,
-)
-Scheduler.create_if_not_exists(
- name: 'Import Jobs',
- method: 'ImportJob.start_registered',
- period: 1.hour,
- prio: 1,
- active: true,
- updated_by_id: 1,
- created_by_id: 1
-)
-
-Trigger.create_or_update(
- name: 'auto reply (on new tickets)',
- condition: {
- 'ticket.action' => {
- 'operator' => 'is',
- 'value' => 'create',
- },
- 'ticket.state_id' => {
- 'operator' => 'is not',
- 'value' => Ticket::State.by_category(:closed).first.id,
- },
- 'article.type_id' => {
- 'operator' => 'is',
- 'value' => [
- Ticket::Article::Type.lookup(name: 'email').id,
- Ticket::Article::Type.lookup(name: 'phone').id,
- Ticket::Article::Type.lookup(name: 'web').id,
- ],
- },
- 'article.sender_id' => {
- 'operator' => 'is',
- 'value' => Ticket::Article::Sender.lookup(name: 'Customer').id,
- },
- },
- perform: {
- 'notification.email' => {
- 'body' => 'Your request (#{config.ticket_hook}#{ticket.number}) has been received and will be reviewed by our support staff.
-
-
-
-Your #{config.product_name} Team
-
-Zammad, your customer support system ',
- 'recipient' => 'ticket_customer',
- 'subject' => 'Thanks for your inquiry (#{ticket.title})',
- },
- },
- active: true,
- created_by_id: 1,
- updated_by_id: 1,
-)
-Trigger.create_or_update(
- name: 'auto reply (on follow up of tickets)',
- condition: {
- 'ticket.action' => {
- 'operator' => 'is',
- 'value' => 'update',
- },
- 'article.sender_id' => {
- 'operator' => 'is',
- 'value' => Ticket::Article::Sender.lookup(name: 'Customer').id,
- },
- 'article.type_id' => {
- 'operator' => 'is',
- 'value' => [
- Ticket::Article::Type.lookup(name: 'email').id,
- Ticket::Article::Type.lookup(name: 'phone').id,
- Ticket::Article::Type.lookup(name: 'web').id,
- ],
- },
- },
- perform: {
- 'notification.email' => {
- 'body' => 'Your follow up for (#{config.ticket_hook}#{ticket.number}) has been received and will be reviewed by our support staff.
-
-
-
-Your #{config.product_name} Team
-
-Zammad, your customer support system ',
- 'recipient' => 'ticket_customer',
- 'subject' => 'Thanks for your follow up (#{ticket.title})',
- },
- },
- active: false,
- created_by_id: 1,
- updated_by_id: 1,
-)
-
-Trigger.create_or_update(
- name: 'customer notification (on owner change)',
- condition: {
- 'ticket.owner_id' => {
- 'operator' => 'has changed',
- 'pre_condition' => 'current_user.id',
- 'value' => '',
- 'value_completion' => '',
- }
- },
- perform: {
- 'notification.email' => {
- 'body' => 'The owner of ticket (Ticket##{ticket.number}) has changed and is now "#{ticket.owner.firstname} #{ticket.owner.lastname}".
-
-
To provide additional information, please reply to this email or click on the following link:
-#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}
-
-
-Zammad, your customer support system
',
- 'recipient' => 'ticket_customer',
- 'subject' => 'Owner has changed (#{ticket.title})',
- },
- },
- active: false,
- created_by_id: 1,
- updated_by_id: 1,
-)
-
-Karma::Activity.create_or_update(
- name: 'ticket create',
- description: 'You have created a ticket',
- score: 10,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket close',
- description: 'You have closed a ticket',
- score: 5,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket answer 1h',
- description: 'You have answered a ticket within 1h',
- score: 25,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket answer 2h',
- description: 'You have answered a ticket within 2h',
- score: 20,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket answer 12h',
- description: 'You have answered a ticket within 12h',
- score: 10,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket answer 24h',
- description: 'You have answered a ticket within 24h',
- score: 5,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket pending state',
- description: 'Usage of advanced features',
- score: 2,
- once_ttl: 60,
-)
-Karma::Activity.create_or_update(
- name: 'ticket escalated',
- description: 'You have escalated tickets',
- score: -5,
- once_ttl: 60 * 60 * 24,
-)
-Karma::Activity.create_or_update(
- name: 'ticket reminder overdue (+2 days)',
- description: 'You have tickets that are over 2 days overdue',
- score: -5,
- once_ttl: 60 * 60 * 24,
-)
-Karma::Activity.create_or_update(
- name: 'text module',
- description: 'Usage of advanced features',
- score: 4,
- once_ttl: 60 * 30,
-)
-Karma::Activity.create_or_update(
- name: 'tagging',
- description: 'Usage of advanced features',
- score: 4,
- once_ttl: 60 * 60 * 4,
-)
+# this is the __ordered__ list of seed files
+# extend only if needed - try to add your changes
+# to the matching one of the existing files
+seeds = %w(settings user_nr_1 signatures roles permissions groups links ticket_state_types ticket_states ticket_priorities ticket_article_types ticket_article_senders macros community_user_resources overviews channels report_profiles chats networks object_manager_attributes schedulers triggers karma_activities)
+
+# loop and require all seedfiles
+# files will get executed automatically
+seeds.each do |seed|
+ # we use require relative here since
+ # - we the seeds file to get loaded only once
+ # - we want to require it relative to the current path
+ require_relative "seeds/#{seed}.rb"
+end
# reset primary key sequences
DbHelper.import_post
@@ -5775,6 +35,7 @@ Locale.create_if_not_exists(
)
Locale.sync
Translation.sync
+
Calendar.init_setup
# install all packages in auto_install
diff --git a/db/seeds/channels.rb b/db/seeds/channels.rb
new file mode 100644
index 000000000..94bdf200f
--- /dev/null
+++ b/db/seeds/channels.rb
@@ -0,0 +1,27 @@
+Channel.create_if_not_exists(
+ area: 'Email::Notification',
+ options: {
+ outbound: {
+ adapter: 'smtp',
+ options: {
+ host: 'host.example.com',
+ user: '',
+ password: '',
+ ssl: true,
+ },
+ },
+ },
+ group_id: 1,
+ preferences: { online_service_disable: true },
+ active: false,
+)
+Channel.create_if_not_exists(
+ area: 'Email::Notification',
+ options: {
+ outbound: {
+ adapter: 'sendmail',
+ },
+ },
+ preferences: { online_service_disable: true },
+ active: true,
+)
diff --git a/db/seeds/chats.rb b/db/seeds/chats.rb
new file mode 100644
index 000000000..79f6b7314
--- /dev/null
+++ b/db/seeds/chats.rb
@@ -0,0 +1,8 @@
+Chat.create_if_not_exists(
+ name: 'default',
+ max_queue: 5,
+ note: '',
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
diff --git a/db/seeds/community_user_resources.rb b/db/seeds/community_user_resources.rb
new file mode 100644
index 000000000..e57a7c4a6
--- /dev/null
+++ b/db/seeds/community_user_resources.rb
@@ -0,0 +1,44 @@
+org_community = Organization.create_if_not_exists(
+ id: 1,
+ name: 'Zammad Foundation',
+)
+user_community = User.create_or_update(
+ id: 2,
+ login: 'nicole.braun@zammad.org',
+ firstname: 'Nicole',
+ lastname: 'Braun',
+ email: 'nicole.braun@zammad.org',
+ password: '',
+ active: true,
+ roles: [ Role.find_by(name: 'Customer') ],
+ organization_id: org_community.id,
+)
+
+UserInfo.current_user_id = user_community.id
+
+ticket = Ticket.create(
+ group_id: Group.find_by(name: 'Users').id,
+ customer_id: User.find_by(login: 'nicole.braun@zammad.org').id,
+ title: 'Welcome to Zammad!',
+)
+Ticket::Article.create(
+ ticket_id: ticket.id,
+ type_id: Ticket::Article::Type.find_by(name: 'phone').id,
+ sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
+ from: 'Zammad Feedback ',
+ body: 'Welcome!
+
+Thank you for choosing Zammad.
+
+You will find updates and patches at https://zammad.org/. Online
+documentation is available at https://zammad.org/documentation. Get
+involved (discussions, contributing, ...) at https://zammad.org/participate.
+
+Regards,
+
+Your Zammad Team
+',
+ internal: false,
+)
+
+UserInfo.current_user_id = 1
diff --git a/db/seeds/groups.rb b/db/seeds/groups.rb
new file mode 100644
index 000000000..994a22639
--- /dev/null
+++ b/db/seeds/groups.rb
@@ -0,0 +1,8 @@
+Group.create_if_not_exists(
+ id: 1,
+ name: 'Users',
+ signature_id: Signature.first.id,
+ note: 'Standard Group/Pool for Tickets.',
+ updated_by_id: 1,
+ created_by_id: 1
+)
diff --git a/db/seeds/karma_activities.rb b/db/seeds/karma_activities.rb
new file mode 100644
index 000000000..b6a6e0cc0
--- /dev/null
+++ b/db/seeds/karma_activities.rb
@@ -0,0 +1,66 @@
+Karma::Activity.create_or_update(
+ name: 'ticket create',
+ description: 'You have created a ticket',
+ score: 10,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket close',
+ description: 'You have closed a ticket',
+ score: 5,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket answer 1h',
+ description: 'You have answered a ticket within 1h',
+ score: 25,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket answer 2h',
+ description: 'You have answered a ticket within 2h',
+ score: 20,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket answer 12h',
+ description: 'You have answered a ticket within 12h',
+ score: 10,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket answer 24h',
+ description: 'You have answered a ticket within 24h',
+ score: 5,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket pending state',
+ description: 'Usage of advanced features',
+ score: 2,
+ once_ttl: 60,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket escalated',
+ description: 'You have escalated tickets',
+ score: -5,
+ once_ttl: 60 * 60 * 24,
+)
+Karma::Activity.create_or_update(
+ name: 'ticket reminder overdue (+2 days)',
+ description: 'You have tickets that are over 2 days overdue',
+ score: -5,
+ once_ttl: 60 * 60 * 24,
+)
+Karma::Activity.create_or_update(
+ name: 'text module',
+ description: 'Usage of advanced features',
+ score: 4,
+ once_ttl: 60 * 30,
+)
+Karma::Activity.create_or_update(
+ name: 'tagging',
+ description: 'Usage of advanced features',
+ score: 4,
+ once_ttl: 60 * 60 * 4,
+)
diff --git a/db/seeds/links.rb b/db/seeds/links.rb
new file mode 100644
index 000000000..d10923779
--- /dev/null
+++ b/db/seeds/links.rb
@@ -0,0 +1,6 @@
+Link::Type.create_if_not_exists(id: 1, name: 'normal')
+Link::Object.create_if_not_exists(id: 1, name: 'Ticket')
+Link::Object.create_if_not_exists(id: 2, name: 'Announcement')
+Link::Object.create_if_not_exists(id: 3, name: 'Question/Answer')
+Link::Object.create_if_not_exists(id: 4, name: 'Idea')
+Link::Object.create_if_not_exists(id: 5, name: 'Bug')
diff --git a/db/seeds/macros.rb b/db/seeds/macros.rb
new file mode 100644
index 000000000..439bd31ea
--- /dev/null
+++ b/db/seeds/macros.rb
@@ -0,0 +1,18 @@
+Macro.create_if_not_exists(
+ name: 'Close & Tag as Spam',
+ perform: {
+ 'ticket.state_id' => {
+ value: Ticket::State.by_category(:closed).first.id,
+ },
+ 'ticket.tags' => {
+ operator: 'add',
+ value: 'spam',
+ },
+ 'ticket.owner_id' => {
+ pre_condition: 'current_user.id',
+ value: '',
+ },
+ },
+ note: 'example macro',
+ active: true,
+)
diff --git a/db/seeds/networks.rb b/db/seeds/networks.rb
new file mode 100644
index 000000000..4da71d606
--- /dev/null
+++ b/db/seeds/networks.rb
@@ -0,0 +1,100 @@
+network = Network.create_if_not_exists(
+ id: 1,
+ name: 'base',
+)
+
+Network::Category::Type.create_if_not_exists(
+ id: 1,
+ name: 'Announcement',
+)
+Network::Category::Type.create_if_not_exists(
+ id: 2,
+ name: 'Idea',
+)
+Network::Category::Type.create_if_not_exists(
+ id: 3,
+ name: 'Question',
+)
+Network::Category::Type.create_if_not_exists(
+ id: 4,
+ name: 'Bug Report',
+)
+
+Network::Privacy.create_if_not_exists(
+ id: 1,
+ name: 'logged in',
+ key: 'loggedIn',
+)
+Network::Privacy.create_if_not_exists(
+ id: 2,
+ name: 'logged in and moderator',
+ key: 'loggedInModerator',
+)
+Network::Category.create_if_not_exists(
+ id: 1,
+ name: 'Announcements',
+ network_id: network.id,
+ network_category_type_id: Network::Category::Type.find_by(name: 'Announcement').id,
+ network_privacy_id: Network::Privacy.find_by(name: 'logged in and moderator').id,
+ allow_comments: true,
+)
+Network::Category.create_if_not_exists(
+ id: 2,
+ name: 'Questions',
+ network_id: network.id,
+ allow_comments: true,
+ network_category_type_id: Network::Category::Type.find_by(name: 'Question').id,
+ network_privacy_id: Network::Privacy.find_by(name: 'logged in').id,
+)
+Network::Category.create_if_not_exists(
+ id: 3,
+ name: 'Ideas',
+ network_id: network.id,
+ network_category_type_id: Network::Category::Type.find_by(name: 'Idea').id,
+ network_privacy_id: Network::Privacy.find_by(name: 'logged in').id,
+ allow_comments: true,
+)
+Network::Category.create_if_not_exists(
+ id: 4,
+ name: 'Bug Reports',
+ network_id: network.id,
+ network_category_type_id: Network::Category::Type.find_by(name: 'Bug Report').id,
+ network_privacy_id: Network::Privacy.find_by(name: 'logged in').id,
+ allow_comments: true,
+)
+item = Network::Item.create(
+ title: 'Example Announcement',
+ body: 'Some announcement....',
+ network_category_id: Network::Category.find_by(name: 'Announcements').id,
+)
+Network::Item::Comment.create(
+ network_item_id: item.id,
+ body: 'Some comment....',
+)
+item = Network::Item.create(
+ title: 'Example Question?',
+ body: 'Some questions....',
+ network_category_id: Network::Category.find_by(name: 'Questions').id,
+)
+Network::Item::Comment.create(
+ network_item_id: item.id,
+ body: 'Some comment....',
+)
+item = Network::Item.create(
+ title: 'Example Idea',
+ body: 'Some idea....',
+ network_category_id: Network::Category.find_by(name: 'Ideas').id,
+)
+Network::Item::Comment.create(
+ network_item_id: item.id,
+ body: 'Some comment....',
+)
+item = Network::Item.create(
+ title: 'Example Bug Report',
+ body: 'Some bug....',
+ network_category_id: Network::Category.find_by(name: 'Bug Reports').id,
+)
+Network::Item::Comment.create(
+ network_item_id: item.id,
+ body: 'Some comment....',
+)
diff --git a/db/seeds/object_manager_attributes.rb b/db/seeds/object_manager_attributes.rb
new file mode 100644
index 000000000..6e70e8ed6
--- /dev/null
+++ b/db/seeds/object_manager_attributes.rb
@@ -0,0 +1,1667 @@
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'title',
+ display: 'Title',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 200,
+ null: false,
+ translate: false,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_top: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {},
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 15,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'customer_id',
+ display: 'Customer',
+ data_type: 'user_autocompletion',
+ data_option: {
+ relation: 'User',
+ autocapitalize: false,
+ multiple: false,
+ guess: true,
+ null: false,
+ limit: 200,
+ placeholder: 'Enter Person or Organization/Company',
+ minLengt: 2,
+ translate: false,
+ permission: ['ticket.agent'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_top: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {},
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 10,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'type',
+ display: 'Type',
+ data_type: 'select',
+ data_option: {
+ default: '',
+ options: {
+ 'Incident' => 'Incident',
+ 'Problem' => 'Problem',
+ 'Request for Change' => 'Request for Change',
+ },
+ nulloption: true,
+ multiple: false,
+ null: true,
+ translate: true,
+ },
+ editable: true,
+ active: false,
+ screens: {
+ create_middle: {
+ '-all-' => {
+ null: false,
+ item_class: 'column',
+ },
+ },
+ edit: {
+ 'ticket.agent' => {
+ null: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 20,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'group_id',
+ display: 'Group',
+ data_type: 'select',
+ data_option: {
+ default: '',
+ relation: 'Group',
+ relation_condition: { access: 'rw' },
+ nulloption: true,
+ multiple: false,
+ null: false,
+ translate: false,
+ only_shown_if_selectable: true,
+ permission: ['ticket.agent', 'ticket.customer'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {
+ '-all-' => {
+ null: false,
+ item_class: 'column',
+ },
+ },
+ edit: {
+ 'ticket.agent' => {
+ null: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 25,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'owner_id',
+ display: 'Owner',
+ data_type: 'select',
+ data_option: {
+ default: '',
+ relation: 'User',
+ relation_condition: { roles: 'Agent' },
+ nulloption: true,
+ multiple: false,
+ null: true,
+ translate: false,
+ permission: ['ticket.agent'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {
+ '-all-' => {
+ null: true,
+ item_class: 'column',
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 30,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'state_id',
+ display: 'State',
+ data_type: 'select',
+ data_option: {
+ relation: 'TicketState',
+ nulloption: true,
+ multiple: false,
+ null: false,
+ default: Ticket::State.find_by(default_follow_up: true).id,
+ translate: true,
+ filter: Ticket::State.by_category(:viewable).pluck(:id),
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {
+ 'ticket.agent' => {
+ null: false,
+ item_class: 'column',
+ filter: Ticket::State.by_category(:viewable_agent_new).pluck(:id),
+ },
+ 'ticket.customer' => {
+ item_class: 'column',
+ nulloption: false,
+ null: true,
+ filter: Ticket::State.by_category(:viewable_customer_new).pluck(:id),
+ default: Ticket::State.find_by(default_create: true).id,
+ },
+ },
+ edit: {
+ 'ticket.agent' => {
+ nulloption: false,
+ null: false,
+ filter: Ticket::State.by_category(:viewable_agent_edit).pluck(:id),
+ },
+ 'ticket.customer' => {
+ nulloption: false,
+ null: true,
+ filter: Ticket::State.by_category(:viewable_customer_edit).pluck(:id),
+ default: Ticket::State.find_by(default_follow_up: true).id,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 40,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'pending_time',
+ display: 'Pending till',
+ data_type: 'datetime',
+ data_option: {
+ future: true,
+ past: false,
+ diff: 24,
+ null: true,
+ translate: true,
+ required_if: {
+ state_id: Ticket::State.by_category(:pending).pluck(:id),
+ },
+ shown_if: {
+ state_id: Ticket::State.by_category(:pending).pluck(:id),
+ },
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {
+ '-all-' => {
+ null: false,
+ item_class: 'column',
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 41,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'priority_id',
+ display: 'Priority',
+ data_type: 'select',
+ data_option: {
+ relation: 'TicketPriority',
+ nulloption: false,
+ multiple: false,
+ null: false,
+ default: Ticket::Priority.find_by(default_create: true).id,
+ translate: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {
+ 'ticket.agent' => {
+ null: false,
+ item_class: 'column',
+ },
+ },
+ edit: {
+ 'ticket.agent' => {
+ null: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 80,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Ticket',
+ name: 'tags',
+ display: 'Tags',
+ data_type: 'tag',
+ data_option: {
+ type: 'text',
+ null: true,
+ translate: false,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_bottom: {
+ 'ticket.agent' => {
+ null: true,
+ },
+ },
+ edit: {},
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 900,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'TicketArticle',
+ name: 'type_id',
+ display: 'Type',
+ data_type: 'select',
+ data_option: {
+ relation: 'TicketArticleType',
+ nulloption: false,
+ multiple: false,
+ null: false,
+ default: Ticket::Article::Type.lookup(name: 'note').id,
+ translate: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {},
+ edit: {
+ 'ticket.agent' => {
+ null: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 100,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'TicketArticle',
+ name: 'internal',
+ display: 'Visibility',
+ data_type: 'select',
+ data_option: {
+ options: { true: 'internal', false: 'public' },
+ nulloption: false,
+ multiple: false,
+ null: true,
+ default: false,
+ translate: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {},
+ edit: {
+ 'ticket.agent' => {
+ null: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 200,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'TicketArticle',
+ name: 'to',
+ display: 'To',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 1000,
+ null: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_middle: {},
+ edit: {
+ 'ticket.agent' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 300,
+)
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'TicketArticle',
+ name: 'cc',
+ display: 'Cc',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 1000,
+ null: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_top: {},
+ create_middle: {},
+ edit: {
+ 'ticket.agent' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 400,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'TicketArticle',
+ name: 'body',
+ display: 'Text',
+ data_type: 'richtext',
+ data_option: {
+ type: 'richtext',
+ maxlength: 20_000,
+ upload: true,
+ rows: 8,
+ null: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create_top: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 600,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'login',
+ display: 'Login',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 100,
+ null: true,
+ autocapitalize: false,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {},
+ view: {
+ '-all-' => {
+ shown: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 100,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'firstname',
+ display: 'Firstname',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: false,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_agent: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_customer: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 200,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'lastname',
+ display: 'Lastname',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: false,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_agent: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_customer: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 300,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'email',
+ display: 'Email',
+ data_type: 'input',
+ data_option: {
+ type: 'email',
+ maxlength: 150,
+ null: false,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_agent: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_customer: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 400,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'web',
+ display: 'Web',
+ data_type: 'input',
+ data_option: {
+ type: 'url',
+ maxlength: 250,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 500,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'phone',
+ display: 'Phone',
+ data_type: 'input',
+ data_option: {
+ type: 'tel',
+ maxlength: 100,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 600,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'mobile',
+ display: 'Mobile',
+ data_type: 'input',
+ data_option: {
+ type: 'tel',
+ maxlength: 100,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 700,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'fax',
+ display: 'Fax',
+ data_type: 'input',
+ data_option: {
+ type: 'tel',
+ maxlength: 100,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 800,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'organization_id',
+ display: 'Organization',
+ data_type: 'autocompletion_ajax',
+ data_option: {
+ multiple: false,
+ nulloption: true,
+ null: true,
+ relation: 'Organization',
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 900,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'department',
+ display: 'Department',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 200,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: true,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1000,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'street',
+ display: 'Street',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 100,
+ null: true,
+ },
+ editable: true,
+ active: false,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1100,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'zip',
+ display: 'Zip',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 100,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: true,
+ active: false,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1200,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'city',
+ display: 'City',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 100,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: true,
+ active: false,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1300,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'address',
+ display: 'Address',
+ data_type: 'textarea',
+ data_option: {
+ type: 'text',
+ maxlength: 500,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: true,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1350,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'password',
+ display: 'Password',
+ data_type: 'input',
+ data_option: {
+ type: 'password',
+ maxlength: 100,
+ null: true,
+ autocomplete: 'new-password',
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ 'admin.user' => {
+ null: true,
+ },
+ },
+ view: {}
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1400,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'vip',
+ display: 'VIP',
+ data_type: 'boolean',
+ data_option: {
+ null: true,
+ default: false,
+ item_class: 'formGroup--halfSize',
+ options: {
+ false: 'no',
+ true: 'yes',
+ },
+ translate: true,
+ permission: ['admin.user', 'ticket.agent'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1490,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'note',
+ display: 'Note',
+ data_type: 'richtext',
+ data_option: {
+ type: 'text',
+ maxlength: 250,
+ null: true,
+ note: 'Notes are visible to agents only, never to customers.',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1500,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'role_ids',
+ display: 'Permissions',
+ data_type: 'user_permission',
+ data_option: {
+ null: false,
+ item_class: 'checkbox',
+ permission: ['admin.user'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {
+ '-all-' => {
+ null: false,
+ default: [Role.lookup(name: 'Agent').id],
+ },
+ },
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1600,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'User',
+ name: 'active',
+ display: 'Active',
+ data_type: 'active',
+ data_option: {
+ null: true,
+ default: true,
+ permission: ['admin.user', 'ticket.agent'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ signup: {},
+ invite_agent: {},
+ invite_customer: {},
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1800,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'name',
+ display: 'Name',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: false,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 200,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'shared',
+ display: 'Shared organization',
+ data_type: 'boolean',
+ data_option: {
+ null: true,
+ default: true,
+ note: 'Customers in the organization can view each other items.',
+ item_class: 'formGroup--halfSize',
+ options: {
+ true: 'yes',
+ false: 'no',
+ },
+ translate: true,
+ permission: ['admin.organization'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1400,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'domain_assignment',
+ display: 'Domain based assignment',
+ data_type: 'boolean',
+ data_option: {
+ null: true,
+ default: false,
+ note: 'Assign Users based on users domain.',
+ item_class: 'formGroup--halfSize',
+ options: {
+ true: 'yes',
+ false: 'no',
+ },
+ translate: true,
+ permission: ['admin.organization'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1410,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'domain',
+ display: 'Domain',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: true,
+ item_class: 'formGroup--halfSize',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1420,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'note',
+ display: 'Note',
+ data_type: 'richtext',
+ data_option: {
+ type: 'text',
+ maxlength: 250,
+ null: true,
+ note: 'Notes are visible to agents only, never to customers.',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1500,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Organization',
+ name: 'active',
+ display: 'Active',
+ data_type: 'active',
+ data_option: {
+ null: true,
+ default: true,
+ permission: ['admin.organization'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1800,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'name',
+ display: 'Name',
+ data_type: 'input',
+ data_option: {
+ type: 'text',
+ maxlength: 150,
+ null: false,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 200,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'assignment_timeout',
+ display: 'Assignment Timeout',
+ data_type: 'integer',
+ data_option: {
+ maxlength: 150,
+ null: true,
+ note: 'Assignment timeout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.',
+ min: 0,
+ max: 999_999,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 300,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'follow_up_possible',
+ display: 'Follow up possible',
+ data_type: 'select',
+ data_option: {
+ default: 'yes',
+ options: {
+ yes: 'yes',
+ new_ticket: 'do not reopen Ticket but create new Ticket'
+ },
+ null: false,
+ note: 'Follow up for closed ticket possible or not.',
+ translate: true
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 400,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'follow_up_assignment',
+ display: 'Assign Follow Ups',
+ data_type: 'select',
+ data_option: {
+ default: 'yes',
+ options: {
+ true: 'yes',
+ false: 'no',
+ },
+ null: false,
+ note: 'Assign follow up to latest agent again.',
+ translate: true
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 500,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'email_address_id',
+ display: 'Email',
+ data_type: 'select',
+ data_option: {
+ default: '',
+ multiple: false,
+ null: true,
+ relation: 'EmailAddress',
+ nulloption: true,
+ do_not_log: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 600,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'signature_id',
+ display: 'Signature',
+ data_type: 'select',
+ data_option: {
+ default: '',
+ multiple: false,
+ null: true,
+ relation: 'Signature',
+ nulloption: true,
+ do_not_log: true,
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 600,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'note',
+ display: 'Note',
+ data_type: 'richtext',
+ data_option: {
+ type: 'text',
+ maxlength: 250,
+ null: true,
+ note: 'Notes are visible to agents only, never to customers.',
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: true,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1500,
+)
+
+ObjectManager::Attribute.add(
+ force: true,
+ object: 'Group',
+ name: 'active',
+ display: 'Active',
+ data_type: 'active',
+ data_option: {
+ null: true,
+ default: true,
+ permission: ['admin.group'],
+ },
+ editable: false,
+ active: true,
+ screens: {
+ create: {
+ '-all-' => {
+ null: true,
+ },
+ },
+ edit: {
+ '-all-': {
+ null: false,
+ },
+ },
+ view: {
+ '-all-' => {
+ shown: false,
+ },
+ },
+ },
+ to_create: false,
+ to_migrate: false,
+ to_delete: false,
+ position: 1800,
+)
diff --git a/db/seeds/overviews.rb b/db/seeds/overviews.rb
new file mode 100644
index 000000000..80d66a00b
--- /dev/null
+++ b/db/seeds/overviews.rb
@@ -0,0 +1,216 @@
+overview_role = Role.find_by(name: 'Agent')
+Overview.create_if_not_exists(
+ name: 'My assigned Tickets',
+ link: 'my_assigned',
+ prio: 1000,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:open).pluck(:id),
+ },
+ 'ticket.owner_id' => {
+ operator: 'is',
+ pre_condition: 'current_user.id',
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'ASC',
+ },
+ view: {
+ d: %w(title customer group created_at),
+ s: %w(title customer group created_at),
+ m: %w(number title customer group created_at),
+ view_mode_default: 's',
+ },
+)
+
+Overview.create_if_not_exists(
+ name: 'Unassigned & Open',
+ link: 'all_unassigned',
+ prio: 1010,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:work_on_all).pluck(:id),
+ },
+ 'ticket.owner_id' => {
+ operator: 'is',
+ pre_condition: 'not_set',
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'ASC',
+ },
+ view: {
+ d: %w(title customer group created_at),
+ s: %w(title customer group created_at),
+ m: %w(number title customer group created_at),
+ view_mode_default: 's',
+ },
+)
+
+Overview.create_if_not_exists(
+ name: 'My pending reached Tickets',
+ link: 'my_pending_reached',
+ prio: 1020,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:pending_reminder).pluck(:id),
+ },
+ 'ticket.owner_id' => {
+ operator: 'is',
+ pre_condition: 'current_user.id',
+ },
+ 'ticket.pending_time' => {
+ operator: 'within next (relative)',
+ value: 0,
+ range: 'minute',
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'ASC',
+ },
+ view: {
+ d: %w(title customer group created_at),
+ s: %w(title customer group created_at),
+ m: %w(number title customer group created_at),
+ view_mode_default: 's',
+ },
+)
+
+Overview.create_if_not_exists(
+ name: 'Open',
+ link: 'all_open',
+ prio: 1030,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:work_on_all).pluck(:id),
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'ASC',
+ },
+ view: {
+ d: %w(title customer group state owner created_at),
+ s: %w(title customer group state owner created_at),
+ m: %w(number title customer group state owner created_at),
+ view_mode_default: 's',
+ },
+)
+
+Overview.create_if_not_exists(
+ name: 'Pending reached',
+ link: 'all_pending_reached',
+ prio: 1040,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:pending_reminder).pluck(:id),
+ },
+ 'ticket.pending_time' => {
+ operator: 'within next (relative)',
+ value: 0,
+ range: 'minute',
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'ASC',
+ },
+ view: {
+ d: %w(title customer group owner created_at),
+ s: %w(title customer group owner created_at),
+ m: %w(number title customer group owner created_at),
+ view_mode_default: 's',
+ },
+)
+
+Overview.create_if_not_exists(
+ name: 'Escalated',
+ link: 'all_escalated',
+ prio: 1050,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.escalation_at' => {
+ operator: 'within next (relative)',
+ value: '10',
+ range: 'minute',
+ },
+ },
+ order: {
+ by: 'escalation_at',
+ direction: 'ASC',
+ },
+ view: {
+ d: %w(title customer group owner escalation_at),
+ s: %w(title customer group owner escalation_at),
+ m: %w(number title customer group owner escalation_at),
+ view_mode_default: 's',
+ },
+)
+
+overview_role = Role.find_by(name: 'Customer')
+Overview.create_if_not_exists(
+ name: 'My Tickets',
+ link: 'my_tickets',
+ prio: 1100,
+ role_ids: [overview_role.id],
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:viewable).pluck(:id),
+ },
+ 'ticket.customer_id' => {
+ operator: 'is',
+ pre_condition: 'current_user.id',
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'DESC',
+ },
+ view: {
+ d: %w(title customer state created_at),
+ s: %w(number title state created_at),
+ m: %w(number title state created_at),
+ view_mode_default: 's',
+ },
+)
+Overview.create_if_not_exists(
+ name: 'My Organization Tickets',
+ link: 'my_organization_tickets',
+ prio: 1200,
+ role_ids: [overview_role.id],
+ organization_shared: true,
+ condition: {
+ 'ticket.state_id' => {
+ operator: 'is',
+ value: Ticket::State.by_category(:viewable).pluck(:id),
+ },
+ 'ticket.organization_id' => {
+ operator: 'is',
+ pre_condition: 'current_user.organization_id',
+ },
+ },
+ order: {
+ by: 'created_at',
+ direction: 'DESC',
+ },
+ view: {
+ d: %w(title customer state created_at),
+ s: %w(number title customer state created_at),
+ m: %w(number title customer state created_at),
+ view_mode_default: 's',
+ },
+)
diff --git a/db/seeds/permissions.rb b/db/seeds/permissions.rb
new file mode 100644
index 000000000..fbd8e60fa
--- /dev/null
+++ b/db/seeds/permissions.rb
@@ -0,0 +1,361 @@
+Permission.create_if_not_exists(
+ name: 'admin',
+ note: 'Admin Interface',
+ preferences: {},
+)
+Permission.create_if_not_exists(
+ name: 'admin.user',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Users']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.group',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Groups']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.role',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Roles']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.organization',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Organizations']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.overview',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Overviews']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.text_module',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Text Modules']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.macro',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Macros']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.tag',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Tags']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.calendar',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Calendar']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.sla',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['SLA']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.scheduler',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Scheduler']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.report_profile',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Report Profiles']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_web',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Web']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_formular',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Formular']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_email',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Email']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_twitter',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Twitter']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_facebook',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Facebook']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_telegram',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Telegram']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.channel_chat',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Channel - Chat']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.branding',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Branding']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.setting_system',
+ note: 'Manage %s Settings',
+ preferences: {
+ translations: ['System']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.security',
+ note: 'Manage %s Settings',
+ preferences: {
+ translations: ['Security']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.ticket',
+ note: 'Manage %s Settings',
+ preferences: {
+ translations: ['Ticket']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.package',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Packages']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.integration',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Integrations']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.api',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['API']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.object',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Objects']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.translation',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Translations']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.monitoring',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Monitoring']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.maintenance',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Maintenance']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'admin.session',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Sessions']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences',
+ note: 'User Preferences',
+ preferences: {},
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.password',
+ note: 'Change %s',
+ preferences: {
+ translations: ['Password']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.notifications',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Notifications'],
+ required: ['ticket.agent'],
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.access_token',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Token Access']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.language',
+ note: 'Change %s',
+ preferences: {
+ translations: ['Language']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.linked_accounts',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Linked Accounts']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.device',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Devices']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.avatar',
+ note: 'Manage %s',
+ preferences: {
+ translations: ['Avatar']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'user_preferences.calendar',
+ note: 'Access to %s',
+ preferences: {
+ translations: ['Calendars'],
+ required: ['ticket.agent'],
+ },
+)
+
+Permission.create_if_not_exists(
+ name: 'report',
+ note: 'Report Interface',
+ preferences: {},
+)
+Permission.create_if_not_exists(
+ name: 'ticket',
+ note: 'Ticket Interface',
+ preferences: {
+ disabled: true
+ },
+)
+Permission.create_if_not_exists(
+ name: 'ticket.agent',
+ note: 'Access to Agent Tickets based on Group Access',
+ preferences: {
+ not: ['ticket.customer'],
+ plugin: ['groups']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'ticket.customer',
+ note: 'Access to Customer Tickets based on current_user.id and current_user.organization_id',
+ preferences: {
+ not: ['ticket.agent'],
+ },
+)
+Permission.create_if_not_exists(
+ name: 'chat',
+ note: 'Access to %s',
+ preferences: {
+ translations: ['Chat']
+ },
+)
+Permission.create_if_not_exists(
+ name: 'chat.agent',
+ note: 'Access to %s',
+ preferences: {
+ translations: ['Chat'],
+ not: ['chat.customer'],
+ },
+)
+Permission.create_if_not_exists(
+ name: 'cti',
+ note: 'CTI',
+ preferences: {
+ disabled: true
+ },
+)
+Permission.create_if_not_exists(
+ name: 'cti.agent',
+ note: 'Access to %s',
+ preferences: {
+ translations: ['CTI'],
+ not: ['cti.customer'],
+ },
+)
+
+admin = Role.find_by(name: 'Admin')
+admin.permission_grant('user_preferences')
+admin.permission_grant('admin')
+admin.permission_grant('report')
+
+agent = Role.find_by(name: 'Agent')
+agent.permission_grant('user_preferences')
+agent.permission_grant('ticket.agent')
+agent.permission_grant('chat.agent')
+agent.permission_grant('cti.agent')
+
+customer = Role.find_by(name: 'Customer')
+customer.permission_grant('user_preferences.password')
+customer.permission_grant('user_preferences.language')
+customer.permission_grant('user_preferences.linked_accounts')
+customer.permission_grant('user_preferences.avatar')
+customer.permission_grant('ticket.customer')
diff --git a/db/seeds/report_profiles.rb b/db/seeds/report_profiles.rb
new file mode 100644
index 000000000..803bce862
--- /dev/null
+++ b/db/seeds/report_profiles.rb
@@ -0,0 +1,7 @@
+Report::Profile.create_if_not_exists(
+ name: '-all-',
+ condition: {},
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
diff --git a/db/seeds/roles.rb b/db/seeds/roles.rb
new file mode 100644
index 000000000..a1bd66e6f
--- /dev/null
+++ b/db/seeds/roles.rb
@@ -0,0 +1,33 @@
+Role.create_if_not_exists(
+ id: 1,
+ name: 'Admin',
+ note: 'To configure your system.',
+ preferences: {
+ not: ['Customer'],
+ },
+ default_at_signup: false,
+ updated_by_id: 1,
+ created_by_id: 1
+)
+Role.create_if_not_exists(
+ id: 2,
+ name: 'Agent',
+ note: 'To work on Tickets.',
+ default_at_signup: false,
+ preferences: {
+ not: ['Customer'],
+ },
+ updated_by_id: 1,
+ created_by_id: 1
+)
+Role.create_if_not_exists(
+ id: 3,
+ name: 'Customer',
+ note: 'People who create Tickets ask for help.',
+ preferences: {
+ not: %w(Agent Admin),
+ },
+ default_at_signup: true,
+ updated_by_id: 1,
+ created_by_id: 1
+)
diff --git a/db/seeds/schedulers.rb b/db/seeds/schedulers.rb
new file mode 100644
index 000000000..94fbe49f6
--- /dev/null
+++ b/db/seeds/schedulers.rb
@@ -0,0 +1,167 @@
+Scheduler.create_if_not_exists(
+ name: 'Process pending tickets',
+ method: 'Ticket.process_pending',
+ period: 15.minutes,
+ prio: 1,
+ active: true,
+)
+Scheduler.create_if_not_exists(
+ name: 'Process escalation tickets',
+ method: 'Ticket.process_escalation',
+ period: 5.minutes,
+ prio: 1,
+ active: true,
+)
+Scheduler.create_if_not_exists(
+ name: 'Import OTRS diff load',
+ method: 'Import::OTRS.diff_worker',
+ period: 3.minutes,
+ prio: 1,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Check Channels',
+ method: 'Channel.fetch',
+ period: 30.seconds,
+ prio: 1,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Check streams for Channel',
+ method: 'Channel.stream',
+ period: 60.seconds,
+ prio: 1,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Generate Session data',
+ method: 'Sessions.jobs',
+ period: 60.seconds,
+ prio: 1,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Execute jobs',
+ method: 'Job.run',
+ period: 5.minutes,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Cleanup expired sessions',
+ method: 'SessionHelper.cleanup_expired',
+ period: 60 * 60 * 12,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Delete old activity stream entries.',
+ method: 'ActivityStream.cleanup',
+ period: 1.day,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Delete old entries.',
+ method: 'RecentView.cleanup',
+ period: 1.day,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Delete old online notification entries.',
+ method: 'OnlineNotification.cleanup',
+ period: 2.hours,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Delete old token entries.',
+ method: 'Token.cleanup',
+ period: 30.days,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Closed chat sessions where participients are offline.',
+ method: 'Chat.cleanup_close',
+ period: 15.minutes,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Cleanup closed sessions.',
+ method: 'Chat.cleanup',
+ period: 5.days,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Sync calendars with ical feeds.',
+ method: 'Calendar.sync',
+ period: 1.day,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Generate user based stats.',
+ method: 'Stats.generate',
+ period: 11.minutes,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_or_update(
+ name: 'Delete old stats store entries.',
+ method: 'StatsStore.cleanup',
+ period: 31.days,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Cleanup HttpLog',
+ method: 'HttpLog.cleanup',
+ period: 1.day,
+ prio: 2,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+)
+Scheduler.create_if_not_exists(
+ name: 'Import Jobs',
+ method: 'ImportJob.start_registered',
+ period: 1.hour,
+ prio: 1,
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1
+)
diff --git a/db/seeds/settings.rb b/db/seeds/settings.rb
new file mode 100644
index 000000000..cec9085ef
--- /dev/null
+++ b/db/seeds/settings.rb
@@ -0,0 +1,2798 @@
+Setting.create_if_not_exists(
+ title: 'Application secret',
+ name: 'application_secret',
+ area: 'Core',
+ description: 'Defines the random application secret.',
+ options: {},
+ state: SecureRandom.hex(128),
+ preferences: {
+ permission: ['admin'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'System Init Done',
+ name: 'system_init_done',
+ area: 'Core',
+ description: 'Defines if application is in init mode.',
+ options: {},
+ state: false,
+ preferences: { online_service_disable: true },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'App Version',
+ name: 'app_version',
+ area: 'Core::WebApp',
+ description: 'Only used internally to propagate current web app version to clients.',
+ options: {},
+ state: '',
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Maintenance Mode',
+ name: 'maintenance_mode',
+ area: 'Core::WebApp',
+ description: 'Enable or disable the maintenance mode of Zammad. If enabled, all non-administrators get logged out and only administrators can start a new session.',
+ options: {},
+ state: false,
+ preferences: {
+ permission: ['admin.maintenance'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Maintenance Login',
+ name: 'maintenance_login',
+ area: 'Core::WebApp',
+ description: 'Put a message on the login page. To change it, click on the text area below and change it inline.',
+ options: {},
+ state: false,
+ preferences: {
+ permission: ['admin.maintenance'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Maintenance Login',
+ name: 'maintenance_login_message',
+ area: 'Core::WebApp',
+ description: 'Message for login page.',
+ options: {},
+ state: 'Something about to share. Click here to change.',
+ preferences: {
+ permission: ['admin.maintenance'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Developer System',
+ name: 'developer_mode',
+ area: 'Core::Develop',
+ description: 'Defines if application is in developer mode (useful for developer, all users have the same password, password reset will work without email delivery).',
+ options: {},
+ state: false,
+ preferences: { online_service_disable: true },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Online Service',
+ name: 'system_online_service',
+ area: 'Core',
+ description: 'Defines if application is used as online service.',
+ options: {},
+ state: false,
+ preferences: { online_service_disable: true },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Product Name',
+ name: 'product_name',
+ area: 'System::Branding',
+ description: 'Defines the name of the application, shown in the web interface, tabs and title bar of the web browser.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'product_name',
+ tag: 'input',
+ },
+ ],
+ },
+ preferences: {
+ render: true,
+ prio: 1,
+ placeholder: true,
+ permission: ['admin.branding'],
+ },
+ state: 'Zammad Helpdesk',
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Logo',
+ name: 'product_logo',
+ area: 'System::Branding',
+ description: 'Defines the logo of the application, shown in the web interface.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'product_logo',
+ tag: 'input',
+ },
+ ],
+ },
+ preferences: {
+ prio: 3,
+ controller: 'SettingsAreaLogo',
+ permission: ['admin.branding'],
+ },
+ state: 'logo.svg',
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Organization',
+ name: 'organization',
+ area: 'System::Branding',
+ description: 'Will be shown in the app and is included in email footers.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'organization',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ preferences: {
+ prio: 2,
+ placeholder: true,
+ permission: ['admin.branding'],
+ },
+ frontend: true
+)
+Setting.create_or_update(
+ title: 'Pretty Date',
+ name: 'pretty_date_format',
+ area: 'System::Branding',
+ description: 'Defines pretty date format.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'pretty_date_format',
+ tag: 'select',
+ options: {
+ 'relative': 'relative - e. g. "2 hours ago" or "2 days and 15 minutes ago"',
+ 'absolute': 'absolute - e. g. "Monday 09:30" or "Tuesday 23. Feb 14:20"',
+ },
+ },
+ ],
+ },
+ preferences: {
+ render: true,
+ prio: 10,
+ permission: ['admin.branding'],
+ },
+ state: 'relative',
+ frontend: true
+)
+options = {}
+(10..99).each { |item|
+ options[item] = item
+}
+system_id = rand(10..99)
+Setting.create_if_not_exists(
+ title: 'SystemID',
+ name: 'system_id',
+ area: 'System::Base',
+ description: 'Defines the system identifier. Every ticket number contains this ID. This ensures that only tickets which belong to your system will be processed as follow-ups (useful when communicating between two instances of Zammad).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'system_id',
+ tag: 'select',
+ options: options,
+ },
+ ],
+ },
+ state: system_id,
+ preferences: {
+ online_service_disable: true,
+ placeholder: true,
+ authentication: true,
+ permission: ['admin.system'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Fully Qualified Domain Name',
+ name: 'fqdn',
+ area: 'System::Base',
+ description: 'Defines the fully qualified domain name of the system. This setting is used as a variable, #{setting.fqdn} which is found in all forms of messaging used by the application, to build links to the tickets within your system.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'fqdn',
+ tag: 'input',
+ },
+ ],
+ },
+ state: 'zammad.example.com',
+ preferences: {
+ online_service_disable: true,
+ placeholder: true,
+ permission: ['admin.system'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Websocket port',
+ name: 'websocket_port',
+ area: 'System::WebSocket',
+ description: 'Defines the port of the websocket server.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'websocket_port',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '6042',
+ preferences: { online_service_disable: true },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'HTTP type',
+ name: 'http_type',
+ area: 'System::Base',
+ description: 'Define the http protocol of your instance.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'http_type',
+ tag: 'select',
+ options: {
+ 'https' => 'https',
+ 'http' => 'http',
+ },
+ },
+ ],
+ },
+ state: 'http',
+ preferences: {
+ online_service_disable: true,
+ placeholder: true,
+ permission: ['admin.system'],
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Storage Mechanism',
+ name: 'storage_provider',
+ area: 'System::Storage',
+ description: '"Database" stores all attachments in the database (not recommended for storing large amounts of data). "Filesystem" stores the data in the filesystem. You can switch between the modules even on a system that is already in production without any loss of data.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'storage_provider',
+ tag: 'select',
+ tranlate: true,
+ options: {
+ 'DB' => 'Database',
+ 'File' => 'Filesystem',
+ },
+ },
+ ],
+ },
+ state: 'DB',
+ preferences: {
+ controller: 'SettingsAreaStorageProvider',
+ online_service_disable: true,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Image Service',
+ name: 'image_backend',
+ area: 'System::Services',
+ description: 'Defines the backend for user and organization image lookups.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'image_backend',
+ tag: 'select',
+ options: {
+ '' => '-',
+ 'Service::Image::Zammad' => 'Zammad Image Service',
+ },
+ },
+ ],
+ },
+ state: 'Service::Image::Zammad',
+ preferences: {
+ prio: 1,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Geo IP Service',
+ name: 'geo_ip_backend',
+ area: 'System::Services',
+ description: 'Defines the backend for geo IP lookups. Shows also location of an IP address if an IP address is shown.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'geo_ip_backend',
+ tag: 'select',
+ options: {
+ '' => '-',
+ 'Service::GeoIp::Zammad' => 'Zammad GeoIP Service',
+ },
+ },
+ ],
+ },
+ state: 'Service::GeoIp::Zammad',
+ preferences: {
+ prio: 2,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Geo Location Service',
+ name: 'geo_location_backend',
+ area: 'System::Services',
+ description: 'Defines the backend for geo location lookups to store geo locations for addresses.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'geo_location_backend',
+ tag: 'select',
+ options: {
+ '' => '-',
+ 'Service::GeoLocation::Gmaps' => 'Google Maps',
+ },
+ },
+ ],
+ },
+ state: 'Service::GeoLocation::Gmaps',
+ preferences: {
+ prio: 3,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Geo Calendar Service',
+ name: 'geo_calendar_backend',
+ area: 'System::Services',
+ description: 'Defines the backend for geo calendar lookups. Used for initial calendar succession.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'geo_calendar_backend',
+ tag: 'select',
+ options: {
+ '' => '-',
+ 'Service::GeoCalendar::Zammad' => 'Zammad GeoCalendar Service',
+ },
+ },
+ ],
+ },
+ state: 'Service::GeoCalendar::Zammad',
+ preferences: {
+ prio: 2,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Proxy Settings',
+ name: 'proxy',
+ area: 'System::Network',
+ description: 'Address of the proxy server for http and https resources.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'proxy',
+ tag: 'input',
+ placeholder: 'proxy.example.com:3128',
+ },
+ ],
+ },
+ state: '',
+ preferences: {
+ online_service_disable: true,
+ controller: 'SettingsAreaProxy',
+ prio: 1,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Proxy User',
+ name: 'proxy_username',
+ area: 'System::Network',
+ description: 'Username for proxy connection.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'proxy_username',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ preferences: {
+ disabled: true,
+ online_service_disable: true,
+ prio: 2,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Proxy Password',
+ name: 'proxy_password',
+ area: 'System::Network',
+ description: 'Password for proxy connection.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'proxy_passowrd',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ preferences: {
+ disabled: true,
+ online_service_disable: true,
+ prio: 3,
+ permission: ['admin.system'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Send client stats',
+ name: 'ui_send_client_stats',
+ area: 'System::UI',
+ description: 'Send client stats/error message to central server to improve the usability.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ui_send_client_stats',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ permission: ['admin.system'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Client storage',
+ name: 'ui_client_storage',
+ area: 'System::UI',
+ description: 'Use client storage to cache data to enhance performance of application.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ui_client_storage',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 2,
+ permission: ['admin.system'],
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Define default visibility of new a new article',
+ name: 'ui_ticket_zoom_article_new_internal',
+ area: 'UI::TicketZoom',
+ description: 'Set default visibility of new a new article.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ui_ticket_zoom_article_new_internal',
+ tag: 'boolean',
+ translate: true,
+ options: {
+ true => 'internal',
+ false => 'public',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ prio: 1,
+ permission: ['admin.ui'],
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'New User Accounts',
+ name: 'user_create_account',
+ area: 'Security::Base',
+ description: 'Enables users to create their own account via web interface.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'user_create_account',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Lost Password',
+ name: 'user_lost_password',
+ area: 'Security::Base',
+ description: 'Activates lost password feature for users.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'user_lost_password',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_ldap',
+ area: 'Security::Authentication',
+ description: 'Enables user authentication via %s.',
+ preferences: {
+ title_i18n: ['LDAP'],
+ description_i18n: ['LDAP'],
+ permission: ['admin.security'],
+ },
+ state: {
+ adapter: 'Auth::Ldap',
+ host: 'localhost',
+ port: 389,
+ bind_dn: 'cn=Manager,dc=example,dc=org',
+ bind_pw: 'example',
+ uid: 'mail',
+ base: 'dc=example,dc=org',
+ always_filter: '',
+ always_roles: %w(Admin Agent),
+ always_groups: ['Users'],
+ sync_params: {
+ firstname: 'sn',
+ lastname: 'givenName',
+ email: 'mail',
+ login: 'mail',
+ },
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_twitter',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_twitter',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_twitter_credentials'],
+ title_i18n: ['Twitter'],
+ description_i18n: ['Twitter', 'Twitter Developer Site', 'https://dev.twitter.com/apps'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Twitter App Credentials',
+ name: 'auth_twitter_credentials',
+ area: 'Security::ThirdPartyAuthentication::Twitter',
+ description: 'App credentials for Twitter.',
+ options: {
+ form: [
+ {
+ display: 'Twitter Key',
+ null: true,
+ name: 'key',
+ tag: 'input',
+ },
+ {
+ display: 'Twitter Secret',
+ null: true,
+ name: 'secret',
+ tag: 'input',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_facebook',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_facebook',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_facebook_credentials'],
+ title_i18n: ['Facebook'],
+ description_i18n: ['Facebook', 'Facebook Developer Site', 'https://developers.facebook.com/apps/'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Facebook App Credentials',
+ name: 'auth_facebook_credentials',
+ area: 'Security::ThirdPartyAuthentication::Facebook',
+ description: 'App credentials for Facebook.',
+ options: {
+ form: [
+ {
+ display: 'App ID',
+ null: true,
+ name: 'app_id',
+ tag: 'input',
+ },
+ {
+ display: 'App Secret',
+ null: true,
+ name: 'app_secret',
+ tag: 'input',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_google_oauth2',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_google_oauth2',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_google_oauth2_credentials'],
+ title_i18n: ['Google'],
+ description_i18n: ['Google', 'Google API Console Site', 'https://console.developers.google.com/apis/credentials'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Google App Credentials',
+ name: 'auth_google_oauth2_credentials',
+ area: 'Security::ThirdPartyAuthentication::Google',
+ description: 'Enables user authentication via Google.',
+ options: {
+ form: [
+ {
+ display: 'Client ID',
+ null: true,
+ name: 'client_id',
+ tag: 'input',
+ },
+ {
+ display: 'Client Secret',
+ null: true,
+ name: 'client_secret',
+ tag: 'input',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_linkedin',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_linkedin',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_linkedin_credentials'],
+ title_i18n: ['LinkedIn'],
+ description_i18n: ['LinkedIn', 'Linkedin Developer Site', 'https://www.linkedin.com/developer/apps'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'LinkedIn App Credentials',
+ name: 'auth_linkedin_credentials',
+ area: 'Security::ThirdPartyAuthentication::Linkedin',
+ description: 'Enables user authentication via LinkedIn.',
+ options: {
+ form: [
+ {
+ display: 'App ID',
+ null: true,
+ name: 'app_id',
+ tag: 'input',
+ },
+ {
+ display: 'App Secret',
+ null: true,
+ name: 'app_secret',
+ tag: 'input',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_github',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_github',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_github_credentials'],
+ title_i18n: ['Github'],
+ description_i18n: ['Github', 'Github OAuth Applications', 'https://github.com/settings/applications'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Github App Credentials',
+ name: 'auth_github_credentials',
+ area: 'Security::ThirdPartyAuthentication::Github',
+ description: 'Enables user authentication via Github.',
+ options: {
+ form: [
+ {
+ display: 'App ID',
+ null: true,
+ name: 'app_id',
+ tag: 'input',
+ },
+ {
+ display: 'App Secret',
+ null: true,
+ name: 'app_secret',
+ tag: 'input',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_gitlab',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via %s. Register your app first at [%s](%s).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_gitlab',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_gitlab_credentials'],
+ title_i18n: ['Gitlab'],
+ description_i18n: ['Gitlab', 'Gitlab Applications', 'https://your-gitlab-host/admin/applications'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Gitlab App Credentials',
+ name: 'auth_gitlab_credentials',
+ area: 'Security::ThirdPartyAuthentication::Gitlab',
+ description: 'Enables user authentication via Gitlab.',
+ options: {
+ form: [
+ {
+ display: 'App ID',
+ null: true,
+ name: 'app_id',
+ tag: 'input',
+ },
+ {
+ display: 'App Secret',
+ null: true,
+ name: 'app_secret',
+ tag: 'input',
+ },
+ {
+ display: 'Site',
+ null: true,
+ name: 'site',
+ tag: 'input',
+ placeholder: 'https://gitlab.YOURDOMAIN.com',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_oauth2',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables user authentication via generic OAuth2. Register your app first.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_oauth2',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: ['auth_oauth2_credentials'],
+ title_i18n: ['Generic OAuth2'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Generic OAuth2 App Credentials',
+ name: 'auth_oauth2_credentials',
+ area: 'Security::ThirdPartyAuthentication::GenericOAuth',
+ description: 'Enables user authentication via generic OAuth2.',
+ options: {
+ form: [
+ {
+ display: 'Name',
+ null: true,
+ name: 'name',
+ tag: 'input',
+ placeholder: 'Some Provider Name',
+ },
+ {
+ display: 'App ID',
+ null: true,
+ name: 'app_id',
+ tag: 'input',
+ },
+ {
+ display: 'App Secret',
+ null: true,
+ name: 'app_secret',
+ tag: 'input',
+ },
+ {
+ display: 'Site',
+ null: true,
+ name: 'site',
+ tag: 'input',
+ placeholder: 'https://gitlab.YOURDOMAIN.com',
+ },
+ {
+ display: 'authorize_url',
+ null: true,
+ name: 'authorize_url',
+ tag: 'input',
+ placeholder: '/oauth/authorize',
+ },
+ {
+ display: 'token_url',
+ null: true,
+ name: 'token_url',
+ tag: 'input',
+ placeholder: '/oauth/token',
+ },
+ ],
+ },
+ state: {},
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Minimum length',
+ name: 'password_min_size',
+ area: 'Security::Password',
+ description: 'Password needs to have at least a minimal number of characters.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'password_min_size',
+ tag: 'select',
+ options: {
+ 4 => ' 4',
+ 5 => ' 5',
+ 6 => ' 6',
+ 7 => ' 7',
+ 8 => ' 8',
+ 9 => ' 9',
+ 10 => '10',
+ 11 => '11',
+ 12 => '12',
+ 13 => '13',
+ 14 => '14',
+ 15 => '15',
+ 16 => '16',
+ 17 => '17',
+ 18 => '18',
+ 19 => '19',
+ 20 => '20',
+ },
+ },
+ ],
+ },
+ state: 6,
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: '2 lower and 2 upper characters',
+ name: 'password_min_2_lower_2_upper_characters',
+ area: 'Security::Password',
+ description: 'Password needs to contain 2 lower and 2 upper characters.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'password_min_2_lower_2_upper_characters',
+ tag: 'select',
+ options: {
+ 1 => 'yes',
+ 0 => 'no',
+ },
+ },
+ ],
+ },
+ state: 0,
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Digit required',
+ name: 'password_need_digit',
+ area: 'Security::Password',
+ description: 'Password needs to contain at least one digit.',
+ options: {
+ form: [
+ {
+ display: 'Needed',
+ null: true,
+ name: 'password_need_digit',
+ tag: 'select',
+ options: {
+ 1 => 'yes',
+ 0 => 'no',
+ },
+ },
+ ],
+ },
+ state: 1,
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Maximum failed logins',
+ name: 'password_max_login_failed',
+ area: 'Security::Password',
+ description: 'Number of failed logins after account will be deactivated.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'password_max_login_failed',
+ tag: 'select',
+ options: {
+ 4 => ' 4',
+ 5 => ' 5',
+ 6 => ' 6',
+ 7 => ' 7',
+ 8 => ' 8',
+ 9 => ' 9',
+ 10 => '10',
+ 11 => '11',
+ 13 => '13',
+ 14 => '14',
+ 15 => '15',
+ 16 => '16',
+ 17 => '17',
+ 18 => '18',
+ 19 => '19',
+ 20 => '20',
+ },
+ },
+ ],
+ },
+ state: 10,
+ preferences: {
+ permission: ['admin.security'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Ticket Hook',
+ name: 'ticket_hook',
+ area: 'Ticket::Base',
+ description: 'The identifier for a ticket, e. g. Ticket#, Call#, MyTicket#. The default is Ticket#.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'ticket_hook',
+ tag: 'input',
+ },
+ ],
+ },
+ preferences: {
+ render: true,
+ placeholder: true,
+ authentication: true,
+ permission: ['admin.ticket'],
+ },
+ state: 'Ticket#',
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Ticket Hook Divider',
+ name: 'ticket_hook_divider',
+ area: 'Ticket::Base::Shadow',
+ description: 'The divider between TicketHook and ticket number. E. g. \': \'.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ticket_hook_divider',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ preferences: {
+ permission: ['admin.ticket'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Ticket Hook Position',
+ name: 'ticket_hook_position',
+ area: 'Ticket::Base',
+ description: "The format of the subject.
+* **Right** means **Some Subject [Ticket#12345]**
+* **Left** means **[Ticket#12345] Some Subject**
+* **None** means **Some Subject** (without ticket number). In the last case you should enable *postmaster_follow_up_search_in* to recognize follow-ups based on email headers and/or body.",
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ticket_hook_position',
+ tag: 'select',
+ translate: true,
+ options: {
+ 'left' => 'left',
+ 'right' => 'right',
+ 'none' => 'none',
+ },
+ },
+ ],
+ },
+ state: 'right',
+ preferences: {
+ controller: 'SettingsAreaTicketHookPosition',
+ permission: ['admin.ticket'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Ticket Number Format',
+ name: 'ticket_number',
+ area: 'Ticket::Number',
+ description: "Selects the ticket number generator module.
+* **Increment** increments the ticket number, the SystemID and the counter are used with SystemID.Counter format (e.g. 1010138, 1010139).
+* With **Date** the ticket numbers will be generated by the current date, the SystemID and the counter. The format looks like Year.Month.Day.SystemID.counter (e.g. 201206231010138, 201206231010139).",
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ticket_number',
+ tag: 'select',
+ translate: true,
+ options: {
+ 'Ticket::Number::Increment' => 'Increment (SystemID.Counter)',
+ 'Ticket::Number::Date' => 'Date (Year.Month.Day.SystemID.Counter)',
+ },
+ },
+ ],
+ },
+ state: 'Ticket::Number::Increment',
+ preferences: {
+ settings_included: %w(ticket_number_increment ticket_number_date),
+ controller: 'SettingsAreaTicketNumber',
+ permission: ['admin.ticket'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Ticket Number Increment',
+ name: 'ticket_number_increment',
+ area: 'Ticket::Number',
+ description: '-',
+ options: {
+ form: [
+ {
+ display: 'Checksum',
+ null: true,
+ name: 'checksum',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ {
+ display: 'Min. size of number',
+ null: true,
+ name: 'min_size',
+ tag: 'select',
+ options: {
+ 1 => ' 1',
+ 2 => ' 2',
+ 3 => ' 3',
+ 4 => ' 4',
+ 5 => ' 5',
+ 6 => ' 6',
+ 7 => ' 7',
+ 8 => ' 8',
+ 9 => ' 9',
+ 10 => '10',
+ 11 => '11',
+ 12 => '12',
+ 13 => '13',
+ 14 => '14',
+ 15 => '15',
+ 16 => '16',
+ 17 => '17',
+ 18 => '18',
+ 19 => '19',
+ 20 => '20',
+ },
+ },
+ ],
+ },
+ state: {
+ checksum: false,
+ min_size: 5,
+ },
+ preferences: {
+ permission: ['admin.ticket'],
+ hidden: true,
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Ticket Number Increment Date',
+ name: 'ticket_number_date',
+ area: 'Ticket::Number',
+ description: '-',
+ options: {
+ form: [
+ {
+ display: 'Checksum',
+ null: true,
+ name: 'checksum',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: {
+ checksum: false
+ },
+ preferences: {
+ permission: ['admin.ticket'],
+ hidden: true,
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Enable Ticket creation',
+ name: 'customer_ticket_create',
+ area: 'CustomerWeb::Base',
+ description: 'Defines if a customer can create tickets via the web interface.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'customer_ticket_create',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ authentication: true,
+ permission: ['admin.channel_web'],
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Group selection for Ticket creation',
+ name: 'customer_ticket_create_group_ids',
+ area: 'CustomerWeb::Base',
+ description: 'Defines groups for which a customer can create tickets via web interface. "-" means all groups are available.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'group_ids',
+ tag: 'select',
+ multiple: true,
+ nulloption: true,
+ relation: 'Group',
+ },
+ ],
+ },
+ state: '',
+ preferences: {
+ authentication: true,
+ permission: ['admin.channel_web'],
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Enable Ticket creation',
+ name: 'form_ticket_create',
+ area: 'Form::Base',
+ description: 'Defines if tickets can be created via web form.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'form_ticket_create',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ permission: ['admin.channel_formular'],
+ },
+ frontend: false,
+)
+
+Setting.create_if_not_exists(
+ title: 'Ticket Subject Size',
+ name: 'ticket_subject_size',
+ area: 'Email::Base',
+ description: 'Max. length of the subject in an email reply.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'ticket_subject_size',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '110',
+ preferences: {
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Ticket Subject Reply',
+ name: 'ticket_subject_re',
+ area: 'Email::Base',
+ description: 'The text at the beginning of the subject in an email reply, e. g. RE, AW, or AS.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ticket_subject_re',
+ tag: 'input',
+ },
+ ],
+ },
+ state: 'RE',
+ preferences: {
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Sender Format',
+ name: 'ticket_define_email_from',
+ area: 'Email::Base',
+ description: 'Defines how the From field of emails (sent from answers and email tickets) should look like.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ticket_define_email_from',
+ tag: 'select',
+ options: {
+ SystemAddressName: 'System Address Display Name',
+ AgentNameSystemAddressName: 'Agent Name + FromSeparator + System Address Display Name',
+ },
+ },
+ ],
+ },
+ state: 'AgentNameSystemAddressName',
+ preferences: {
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Sender Format Separator',
+ name: 'ticket_define_email_from_separator',
+ area: 'Email::Base',
+ description: 'Defines the separator between the agent\'s real name and the given group email address.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'ticket_define_email_from_separator',
+ tag: 'input',
+ },
+ ],
+ },
+ state: 'via',
+ preferences: {
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Maximum Email Size',
+ name: 'postmaster_max_size',
+ area: 'Email::Base',
+ description: 'Maximum size in MB of emails.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'postmaster_max_size',
+ tag: 'select',
+ options: {
+ 1 => ' 1',
+ 2 => ' 2',
+ 3 => ' 3',
+ 4 => ' 4',
+ 5 => ' 5',
+ 6 => ' 6',
+ 7 => ' 7',
+ 8 => ' 8',
+ 9 => ' 9',
+ 10 => ' 10',
+ 15 => ' 15',
+ 20 => ' 20',
+ 25 => ' 25',
+ 30 => ' 30',
+ 35 => ' 35',
+ 40 => ' 40',
+ 45 => ' 45',
+ 50 => ' 50',
+ 60 => ' 60',
+ 70 => ' 70',
+ 80 => ' 80',
+ 90 => ' 90',
+ 100 => '100',
+ 125 => '125',
+ 150 => '150',
+ },
+ },
+ ],
+ },
+ state: 10,
+ preferences: {
+ online_service_disable: true,
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Additional follow-up detection',
+ name: 'postmaster_follow_up_search_in',
+ area: 'Email::Base',
+ description: 'By default the follow-up check is done via the subject of an email. With this setting you can add more fields for which the follow-up check will be executed.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'postmaster_follow_up_search_in',
+ tag: 'checkbox',
+ options: {
+ 'references' => 'References - Search for follow up also in In-Reply-To or References headers.',
+ 'body' => 'Body - Search for follow up also in mail body.',
+ 'attachment' => 'Attachment - Search for follow up also in attachments.',
+ },
+ },
+ ],
+ },
+ state: [],
+ preferences: {
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Notification Sender',
+ name: 'notification_sender',
+ area: 'Email::Base',
+ description: 'Defines the sender of email notifications.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'notification_sender',
+ tag: 'input',
+ },
+ ],
+ },
+ state: 'Notification Master ',
+ preferences: {
+ online_service_disable: true,
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Block Notifications',
+ name: 'send_no_auto_response_reg_exp',
+ area: 'Email::Base',
+ description: 'If this regex matches, no notification will be sent by the sender.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'send_no_auto_response_reg_exp',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '(mailer-daemon|postmaster|abuse|root|noreply|noreply.+?|no-reply|no-reply.+?)@.+?\..+?',
+ preferences: {
+ online_service_disable: true,
+ permission: ['admin.channel_email'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'API Token Access',
+ name: 'api_token_access',
+ area: 'API::Base',
+ description: 'Enable REST API using tokens (not username/email address and password). Each user needs to create its own access tokens in user profile.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'api_token_access',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ permission: ['admin.api'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'API Password Access',
+ name: 'api_password_access',
+ area: 'API::Base',
+ description: 'Enable REST API access using the username/email address and password for the authentication user.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'api_password_access',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ permission: ['admin.api'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Monitoring Token',
+ name: 'monitoring_token',
+ area: 'HealthCheck::Base',
+ description: 'Token for monitoring.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'monitoring_token',
+ tag: 'input',
+ },
+ ],
+ },
+ state: SecureRandom.urlsafe_base64(40),
+ preferences: {
+ permission: ['admin.monitoring'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Enable Chat',
+ name: 'chat',
+ area: 'Chat::Base',
+ description: 'Enable/disable online chat.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'chat',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ trigger: ['menu:render', 'chat:rerender'],
+ permission: ['admin.channel_chat'],
+ },
+ state: false,
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Agent idle timeout',
+ name: 'chat_agent_idle_timeout',
+ area: 'Chat::Extended',
+ description: 'Idle timeout in seconds until agent is set offline automatically.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'chat_agent_idle_timeout',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '120',
+ preferences: {
+ permission: ['admin.channel_chat'],
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Defines searchable models.',
+ name: 'models_searchable',
+ area: 'Models::Base',
+ description: 'Defines the searchable models.',
+ options: {},
+ state: [],
+ preferences: {
+ authentication: true,
+ },
+ frontend: true,
+)
+
+Setting.create_if_not_exists(
+ title: 'Default Screen',
+ name: 'default_controller',
+ area: 'Core',
+ description: 'Defines the default screen.',
+ options: {},
+ state: '#dashboard',
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Elasticsearch Endpoint URL',
+ name: 'es_url',
+ area: 'SearchIndex::Elasticsearch',
+ description: 'Defines endpoint of Elasticsearch.',
+ state: '',
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Elasticsearch Endpoint User',
+ name: 'es_user',
+ area: 'SearchIndex::Elasticsearch',
+ description: 'Defines HTTP basic auth user of Elasticsearch.',
+ state: '',
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Elasticsearch Endpoint Password',
+ name: 'es_password',
+ area: 'SearchIndex::Elasticsearch',
+ description: 'Defines HTTP basic auth password of Elasticsearch.',
+ state: '',
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Elasticsearch Endpoint Index',
+ name: 'es_index',
+ area: 'SearchIndex::Elasticsearch',
+ description: 'Defines Elasticsearch index name.',
+ state: 'zammad',
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Elasticsearch Attachment Extensions',
+ name: 'es_attachment_ignore',
+ area: 'SearchIndex::Elasticsearch',
+ description: 'Defines attachment extensions which will be ignored by Elasticsearch.',
+ state: [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe', '.box', '.mbox' ],
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Elasticsearch Attachment Size',
+ name: 'es_attachment_max_size_in_mb',
+ area: 'SearchIndex::Elasticsearch',
+ description: 'Define max. attachment size for Elasticsearch.',
+ state: 50,
+ preferences: { online_service_disable: true },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Import Mode',
+ name: 'import_mode',
+ area: 'Import::Base',
+ description: 'Puts Zammad into import mode (disables some triggers).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'import_mode',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Import Backend',
+ name: 'import_backend',
+ area: 'Import::Base::Internal',
+ description: 'Set backend which is being used for import.',
+ options: {},
+ state: '',
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Ignore Escalation/SLA Information',
+ name: 'import_ignore_sla',
+ area: 'Import::Base',
+ description: 'Ignore escalation/SLA information for import.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'import_ignore_sla',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Import Endpoint',
+ name: 'import_otrs_endpoint',
+ area: 'Import::OTRS',
+ description: 'Defines OTRS endpoint to import users, tickets, states and articles.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'import_otrs_endpoint',
+ tag: 'input',
+ },
+ ],
+ },
+ state: 'http://otrs_host/otrs',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Import Key',
+ name: 'import_otrs_endpoint_key',
+ area: 'Import::OTRS',
+ description: 'Defines OTRS endpoint authentication key.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'import_otrs_endpoint_key',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Import User for HTTP basic authentication',
+ name: 'import_otrs_user',
+ area: 'Import::OTRS',
+ description: 'Defines HTTP basic authentication user (only if OTRS is protected via HTTP basic auth).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'import_otrs_user',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Import Password for http basic authentication',
+ name: 'import_otrs_password',
+ area: 'Import::OTRS',
+ description: 'Defines http basic authentication password (only if OTRS is protected via http basic auth).',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'import_otrs_password',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Import Endpoint',
+ name: 'import_zendesk_endpoint',
+ area: 'Import::Zendesk',
+ description: 'Defines Zendesk endpoint to import users, ticket, states and articles.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'import_zendesk_endpoint',
+ tag: 'input',
+ },
+ ],
+ },
+ state: 'https://yours.zendesk.com/api/v2',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Import Key for requesting the Zendesk API',
+ name: 'import_zendesk_endpoint_key',
+ area: 'Import::Zendesk',
+ description: 'Defines Zendesk endpoint authentication key.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'import_zendesk_endpoint_key',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Import User for requesting the Zendesk API',
+ name: 'import_zendesk_endpoint_username',
+ area: 'Import::Zendesk',
+ description: 'Defines Zendesk endpoint authentication user.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'import_zendesk_endpoint_username',
+ tag: 'input',
+ },
+ ],
+ },
+ state: '',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Import Backends',
+ name: 'import_backends',
+ area: 'Import',
+ description: 'A list of active import backends that get scheduled automatically.',
+ options: {},
+ state: ['Import::Ldap'],
+ preferences: {
+ permission: ['admin'],
+ },
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Time Accounting',
+ name: 'time_accounting',
+ area: 'Web::Base',
+ description: 'Enable time accounting.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'time_accounting',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ authentication: true,
+ permission: ['admin.time_accounting'],
+ },
+ state: false,
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Time Accounting Selector',
+ name: 'time_accounting_selector',
+ area: 'Web::Base',
+ description: 'Enable time accounting for these tickets.',
+ options: {
+ form: [
+ {},
+ ],
+ },
+ preferences: {
+ authentication: true,
+ permission: ['admin.time_accounting'],
+ },
+ state: {},
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'New Tags',
+ name: 'tag_new',
+ area: 'Web::Base',
+ description: 'Allow users to create new tags.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'tag_new',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ authentication: true,
+ permission: ['admin.tag'],
+ },
+ state: true,
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Default calendar tickets subscriptions',
+ name: 'defaults_calendar_subscriptions_tickets',
+ area: 'Defaults::CalendarSubscriptions',
+ description: 'Defines the default calendar tickets subscription settings.',
+ options: {},
+ state: {
+ escalation: {
+ own: true,
+ not_assigned: false,
+ },
+ new_open: {
+ own: true,
+ not_assigned: false,
+ },
+ pending: {
+ own: true,
+ not_assigned: false,
+ }
+ },
+ preferences: {
+ authentication: true,
+ },
+ frontend: true
+)
+
+Setting.create_if_not_exists(
+ title: 'Defines translator identifier.',
+ name: 'translator_key',
+ area: 'i18n::translator_key',
+ description: 'Defines the translator identifier for contributions.',
+ options: {},
+ state: '',
+ frontend: false
+)
+
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0010_postmaster_filter_trusted',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to remove X-Zammad headers from not trusted sources.',
+ options: {},
+ state: 'Channel::Filter::Trusted',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0012_postmaster_filter_sender_is_system_address',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to check if email has been created by Zammad itself and will set the article sender.',
+ options: {},
+ state: 'Channel::Filter::SenderIsSystemAddress',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0014_postmaster_filter_own_notification_loop_detection',
+ area: 'Postmaster::PreFilter',
+ description: 'Define postmaster filter to check if email is a own created notification email, then ignore it to prevent email loops.',
+ options: {},
+ state: 'Channel::Filter::OwnNotificationLoopDetection',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0015_postmaster_filter_identify_sender',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to identify sender user.',
+ options: {},
+ state: 'Channel::Filter::IdentifySender',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0020_postmaster_filter_auto_response_check',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to identify auto responses to prevent auto replies from Zammad.',
+ options: {},
+ state: 'Channel::Filter::AutoResponseCheck',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0030_postmaster_filter_out_of_office_check',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to identify out-of-office emails for follow-up detection and keeping current ticket state.',
+ options: {},
+ state: 'Channel::Filter::OutOfOfficeCheck',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0100_postmaster_filter_follow_up_check',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to identify follow-ups (based on admin settings).',
+ options: {},
+ state: 'Channel::Filter::FollowUpCheck',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0200_postmaster_filter_follow_up_possible_check',
+ area: 'Postmaster::PreFilter',
+ description: 'Define postmaster filter to check if follow ups get created (based on admin settings).',
+ options: {},
+ state: 'Channel::Filter::FollowUpPossibleCheck',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '0900_postmaster_filter_bounce_check',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to identify postmaster bounced - to handle it as follow-up of the original ticket.',
+ options: {},
+ state: 'Channel::Filter::BounceCheck',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '1000_postmaster_filter_database_check',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter for filters managed via admin interface.',
+ options: {},
+ state: 'Channel::Filter::Database',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '5000_postmaster_filter_icinga',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to manage Icinga (http://www.icinga.org) emails.',
+ options: {},
+ state: 'Channel::Filter::Icinga',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines postmaster filter.',
+ name: '5100_postmaster_filter_nagios',
+ area: 'Postmaster::PreFilter',
+ description: 'Defines postmaster filter to manage Nagios (http://www.nagios.org) emails.',
+ options: {},
+ state: 'Channel::Filter::Nagios',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Icinga integration',
+ name: 'icinga_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if Icinga (http://www.icinga.org) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'icinga_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Sender',
+ name: 'icinga_sender',
+ area: 'Integration::Icinga',
+ description: 'Defines the sender email address of Icinga emails.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'icinga_sender',
+ tag: 'input',
+ placeholder: 'icinga@monitoring.example.com',
+ },
+ ],
+ },
+ state: 'icinga@monitoring.example.com',
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+)
+Setting.create_if_not_exists(
+ title: 'Auto close',
+ name: 'icinga_auto_close',
+ area: 'Integration::Icinga',
+ description: 'Defines if tickets should be closed if service is recovered.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'icinga_auto_close',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ prio: 3,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Auto close state',
+ name: 'icinga_auto_close_state_id',
+ area: 'Integration::Icinga',
+ description: 'Defines the state of auto closed tickets.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'icinga_auto_close_state_id',
+ tag: 'select',
+ relation: 'TicketState',
+ },
+ ],
+ },
+ state: 4,
+ preferences: {
+ prio: 4,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Nagios integration',
+ name: 'nagios_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if Nagios (http://www.nagios.org) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'nagios_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Sender',
+ name: 'nagios_sender',
+ area: 'Integration::Nagios',
+ description: 'Defines the sender email address of Nagios emails.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'nagios_sender',
+ tag: 'input',
+ placeholder: 'nagios@monitoring.example.com',
+ },
+ ],
+ },
+ state: 'nagios@monitoring.example.com',
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+)
+Setting.create_if_not_exists(
+ title: 'Auto close',
+ name: 'nagios_auto_close',
+ area: 'Integration::Nagios',
+ description: 'Defines if tickets should be closed if service is recovered.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'nagios_auto_close',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: true,
+ preferences: {
+ prio: 3,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Auto close state',
+ name: 'nagios_auto_close_state_id',
+ area: 'Integration::Nagios',
+ description: 'Defines the state of auto closed tickets.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'nagios_auto_close_state_id',
+ tag: 'select',
+ relation: 'TicketState',
+ },
+ ],
+ },
+ state: 4,
+ preferences: {
+ prio: 4,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'LDAP integration',
+ name: 'ldap_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if LDAP is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'ldap_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ authentication: true,
+ permission: ['admin.integration'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'LDAP config',
+ name: 'ldap_config',
+ area: 'Integration::LDAP',
+ description: 'Defines the LDAP config.',
+ options: {},
+ state: {},
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+)
+Setting.create_if_not_exists(
+ title: 'Defines sync transaction backend.',
+ name: '0100_trigger',
+ area: 'Transaction::Backend::Sync',
+ description: 'Defines the transaction backend to execute triggers.',
+ options: {},
+ state: 'Transaction::Trigger',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines transaction backend.',
+ name: '0100_notification',
+ area: 'Transaction::Backend::Async',
+ description: 'Defines the transaction backend to send agent notifications.',
+ options: {},
+ state: 'Transaction::Notification',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines transaction backend.',
+ name: '1000_signature_detection',
+ area: 'Transaction::Backend::Async',
+ description: 'Defines the transaction backend to detect customer signatures in emails.',
+ options: {},
+ state: 'Transaction::SignatureDetection',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines transaction backend.',
+ name: '6000_slack_webhook',
+ area: 'Transaction::Backend::Async',
+ description: 'Defines the transaction backend which posts messages to Slack (http://www.slack.com).',
+ options: {},
+ state: 'Transaction::Slack',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Slack integration',
+ name: 'slack_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if Slack (http://www.slack.org) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'slack_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Slack config',
+ name: 'slack_config',
+ area: 'Integration::Slack',
+ description: 'Defines the slack config.',
+ options: {},
+ state: {
+ items: []
+ },
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+)
+Setting.create_if_not_exists(
+ title: 'sipgate.io integration',
+ name: 'sipgate_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if sipgate.io (http://www.sipgate.io) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'sipgate_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ trigger: ['menu:render', 'cti:reload'],
+ authentication: true,
+ permission: ['admin.integration'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'sipgate.io config',
+ name: 'sipgate_config',
+ area: 'Integration::Sipgate',
+ description: 'Defines the sipgate.io config.',
+ options: {},
+ state: {},
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+)
+Setting.create_if_not_exists(
+ title: 'Clearbit integration',
+ name: 'clearbit_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if Clearbit (http://www.clearbit.com) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'clearbit_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Clearbit config',
+ name: 'clearbit_config',
+ area: 'Integration::Clearbit',
+ description: 'Defines the Clearbit config.',
+ options: {},
+ state: {},
+ frontend: false,
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+)
+Setting.create_if_not_exists(
+ title: 'Defines transaction backend.',
+ name: '9000_clearbit_enrichment',
+ area: 'Transaction::Backend::Async',
+ description: 'Defines the transaction backend which will enrich customer and organization information from Clearbit (http://www.clearbit.com).',
+ options: {},
+ state: 'Transaction::ClearbitEnrichment',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines transaction backend.',
+ name: '9100_cti_caller_id_detection',
+ area: 'Transaction::Backend::Async',
+ description: 'Defines the transaction backend which detects caller IDs in objects and store them for CTI lookups.',
+ options: {},
+ state: 'Transaction::CtiCallerIdDetection',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines transaction backend.',
+ name: '9200_karma',
+ area: 'Transaction::Backend::Async',
+ description: 'Defines the transaction backend which creates the karma score.',
+ options: {},
+ state: 'Transaction::Karma',
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Defines karma levels.',
+ name: 'karma_levels',
+ area: 'Core::Karma',
+ description: 'Defines the karma levels.',
+ options: {},
+ state: [
+ {
+ name: 'Beginner',
+ start: 0,
+ end: 499,
+ },
+ {
+ name: 'Newbie',
+ start: 500,
+ end: 1999,
+ },
+ {
+ name: 'Intermediate',
+ start: 2000,
+ end: 4999,
+ },
+ {
+ name: 'Professional',
+ start: 5000,
+ end: 6999,
+ },
+ {
+ name: 'Expert',
+ start: 7000,
+ end: 8999,
+ },
+ {
+ name: 'Master',
+ start: 9000,
+ end: 18_999,
+ },
+ {
+ name: 'Evangelist',
+ start: 19_000,
+ end: 45_999,
+ },
+ {
+ name: 'Hero',
+ start: 50_000,
+ end: nil,
+ },
+ ],
+ frontend: false
+)
+Setting.create_if_not_exists(
+ title: 'Set limit of agents',
+ name: 'system_agent_limit',
+ area: 'Core::Online',
+ description: 'Defines the limit of the agents.',
+ options: {},
+ state: false,
+ preferences: { online_service_disable: true },
+ frontend: false
+)
diff --git a/db/seeds/signatures.rb b/db/seeds/signatures.rb
new file mode 100644
index 000000000..be0948bb5
--- /dev/null
+++ b/db/seeds/signatures.rb
@@ -0,0 +1,14 @@
+Signature.create_if_not_exists(
+ id: 1,
+ name: 'default',
+ body: '
+ #{user.firstname} #{user.lastname}
+
+--
+ Super Support - Waterford Business Park
+ 5201 Blue Lagoon Drive - 8th Floor & 9th Floor - Miami, 33126 USA
+ Email: hot@example.com - Web: http://www.example.com/
+--'.text2html,
+ updated_by_id: 1,
+ created_by_id: 1
+)
diff --git a/db/seeds/ticket_article_senders.rb b/db/seeds/ticket_article_senders.rb
new file mode 100644
index 000000000..c0cb37484
--- /dev/null
+++ b/db/seeds/ticket_article_senders.rb
@@ -0,0 +1,3 @@
+Ticket::Article::Sender.create_if_not_exists(id: 1, name: 'Agent')
+Ticket::Article::Sender.create_if_not_exists(id: 2, name: 'Customer')
+Ticket::Article::Sender.create_if_not_exists(id: 3, name: 'System')
diff --git a/db/seeds/ticket_article_types.rb b/db/seeds/ticket_article_types.rb
new file mode 100644
index 000000000..d81476444
--- /dev/null
+++ b/db/seeds/ticket_article_types.rb
@@ -0,0 +1,12 @@
+Ticket::Article::Type.create_if_not_exists(id: 1, name: 'email', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 2, name: 'sms', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 3, name: 'chat', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 4, name: 'fax', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 5, name: 'phone', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 6, name: 'twitter status', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 7, name: 'twitter direct-message', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 8, name: 'facebook feed post', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 9, name: 'facebook feed comment', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 10, name: 'note', communication: false)
+Ticket::Article::Type.create_if_not_exists(id: 11, name: 'web', communication: true)
+Ticket::Article::Type.create_if_not_exists(id: 12, name: 'telegram personal-message', communication: true)
diff --git a/db/seeds/ticket_priorities.rb b/db/seeds/ticket_priorities.rb
new file mode 100644
index 000000000..543bdde2e
--- /dev/null
+++ b/db/seeds/ticket_priorities.rb
@@ -0,0 +1,3 @@
+Ticket::Priority.create_if_not_exists(id: 1, name: '1 low')
+Ticket::Priority.create_if_not_exists(id: 2, name: '2 normal', default_create: true)
+Ticket::Priority.create_if_not_exists(id: 3, name: '3 high')
diff --git a/db/seeds/ticket_state_types.rb b/db/seeds/ticket_state_types.rb
new file mode 100644
index 000000000..97cb02568
--- /dev/null
+++ b/db/seeds/ticket_state_types.rb
@@ -0,0 +1,7 @@
+Ticket::StateType.create_if_not_exists(id: 1, name: 'new')
+Ticket::StateType.create_if_not_exists(id: 2, name: 'open')
+Ticket::StateType.create_if_not_exists(id: 3, name: 'pending reminder')
+Ticket::StateType.create_if_not_exists(id: 4, name: 'pending action')
+Ticket::StateType.create_if_not_exists(id: 5, name: 'closed')
+Ticket::StateType.create_if_not_exists(id: 6, name: 'merged')
+Ticket::StateType.create_if_not_exists(id: 7, name: 'removed')
diff --git a/db/seeds/ticket_states.rb b/db/seeds/ticket_states.rb
new file mode 100644
index 000000000..e8529c04a
--- /dev/null
+++ b/db/seeds/ticket_states.rb
@@ -0,0 +1,44 @@
+Ticket::State.create_if_not_exists(
+ id: 1,
+ name: 'new',
+ state_type_id: Ticket::StateType.find_by(name: 'new').id,
+ default_create: true,
+)
+Ticket::State.create_if_not_exists(
+ id: 2,
+ name: 'open',
+ state_type_id: Ticket::StateType.find_by(name: 'open').id,
+ default_follow_up: true,
+)
+Ticket::State.create_if_not_exists(
+ id: 3,
+ name: 'pending reminder',
+ state_type_id: Ticket::StateType.find_by(name: 'pending reminder').id,
+ ignore_escalation: true,
+)
+Ticket::State.create_if_not_exists(
+ id: 4,
+ name: 'closed',
+ state_type_id: Ticket::StateType.find_by(name: 'closed').id,
+ ignore_escalation: true,
+)
+Ticket::State.create_if_not_exists(
+ id: 5,
+ name: 'merged',
+ state_type_id: Ticket::StateType.find_by(name: 'merged').id,
+ ignore_escalation: true,
+)
+Ticket::State.create_if_not_exists(
+ id: 6,
+ name: 'removed',
+ state_type_id: Ticket::StateType.find_by(name: 'removed').id,
+ active: false,
+ ignore_escalation: true,
+)
+Ticket::State.create_if_not_exists(
+ id: 7,
+ name: 'pending close',
+ state_type_id: Ticket::StateType.find_by(name: 'pending action').id,
+ next_state_id: Ticket::State.by_category(:closed).first.id,
+ ignore_escalation: true,
+)
diff --git a/db/seeds/triggers.rb b/db/seeds/triggers.rb
new file mode 100644
index 000000000..d921fb9a5
--- /dev/null
+++ b/db/seeds/triggers.rb
@@ -0,0 +1,110 @@
+Trigger.create_or_update(
+ name: 'auto reply (on new tickets)',
+ condition: {
+ 'ticket.action' => {
+ 'operator' => 'is',
+ 'value' => 'create',
+ },
+ 'ticket.state_id' => {
+ 'operator' => 'is not',
+ 'value' => Ticket::State.by_category(:closed).first.id,
+ },
+ 'article.type_id' => {
+ 'operator' => 'is',
+ 'value' => [
+ Ticket::Article::Type.lookup(name: 'email').id,
+ Ticket::Article::Type.lookup(name: 'phone').id,
+ Ticket::Article::Type.lookup(name: 'web').id,
+ ],
+ },
+ 'article.sender_id' => {
+ 'operator' => 'is',
+ 'value' => Ticket::Article::Sender.lookup(name: 'Customer').id,
+ },
+ },
+ perform: {
+ 'notification.email' => {
+ 'body' => 'Your request (#{config.ticket_hook}#{ticket.number}) has been received and will be reviewed by our support staff.
+
+
+
+Your #{config.product_name} Team
+
+Zammad, your customer support system ',
+ 'recipient' => 'ticket_customer',
+ 'subject' => 'Thanks for your inquiry (#{ticket.title})',
+ },
+ },
+ active: true,
+ created_by_id: 1,
+ updated_by_id: 1,
+)
+Trigger.create_or_update(
+ name: 'auto reply (on follow up of tickets)',
+ condition: {
+ 'ticket.action' => {
+ 'operator' => 'is',
+ 'value' => 'update',
+ },
+ 'article.sender_id' => {
+ 'operator' => 'is',
+ 'value' => Ticket::Article::Sender.lookup(name: 'Customer').id,
+ },
+ 'article.type_id' => {
+ 'operator' => 'is',
+ 'value' => [
+ Ticket::Article::Type.lookup(name: 'email').id,
+ Ticket::Article::Type.lookup(name: 'phone').id,
+ Ticket::Article::Type.lookup(name: 'web').id,
+ ],
+ },
+ },
+ perform: {
+ 'notification.email' => {
+ 'body' => 'Your follow up for (#{config.ticket_hook}#{ticket.number}) has been received and will be reviewed by our support staff.
+
+
+
+Your #{config.product_name} Team
+
+Zammad, your customer support system ',
+ 'recipient' => 'ticket_customer',
+ 'subject' => 'Thanks for your follow up (#{ticket.title})',
+ },
+ },
+ active: false,
+ created_by_id: 1,
+ updated_by_id: 1,
+)
+
+Trigger.create_or_update(
+ name: 'customer notification (on owner change)',
+ condition: {
+ 'ticket.owner_id' => {
+ 'operator' => 'has changed',
+ 'pre_condition' => 'current_user.id',
+ 'value' => '',
+ 'value_completion' => '',
+ }
+ },
+ perform: {
+ 'notification.email' => {
+ 'body' => 'The owner of ticket (Ticket##{ticket.number}) has changed and is now "#{ticket.owner.firstname} #{ticket.owner.lastname}".
+
+
To provide additional information, please reply to this email or click on the following link:
+#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}
+
+
+Zammad, your customer support system
',
+ 'recipient' => 'ticket_customer',
+ 'subject' => 'Owner has changed (#{ticket.title})',
+ },
+ },
+ active: false,
+ created_by_id: 1,
+ updated_by_id: 1,
+)
diff --git a/db/seeds/user_nr_1.rb b/db/seeds/user_nr_1.rb
new file mode 100644
index 000000000..2f7032fac
--- /dev/null
+++ b/db/seeds/user_nr_1.rb
@@ -0,0 +1,12 @@
+User.create_if_not_exists(
+ id: 1,
+ login: '-',
+ firstname: '-',
+ lastname: '',
+ email: '',
+ active: false,
+ updated_by_id: 1,
+ created_by_id: 1
+)
+
+UserInfo.current_user_id = 1
From 8ef2970234dab65a00b4189cc230dcff9195de34 Mon Sep 17 00:00:00 2001
From: Thorsten Eckel
Date: Thu, 27 Apr 2017 10:17:10 +0200
Subject: [PATCH 03/31] Added method to perform a yielded action with an
ensured UserInfo.current_user_id and added new and missing tests.
---
lib/user_info.rb | 12 +++++++++++
spec/lib/user_info_spec.rb | 41 ++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
create mode 100644 spec/lib/user_info_spec.rb
diff --git a/lib/user_info.rb b/lib/user_info.rb
index ed6a12761..604e9e964 100644
--- a/lib/user_info.rb
+++ b/lib/user_info.rb
@@ -6,4 +6,16 @@ module UserInfo
def self.current_user_id=(user_id)
Thread.current[:user_id] = user_id
end
+
+ def self.ensure_current_user_id
+ if UserInfo.current_user_id.nil?
+ UserInfo.current_user_id = 1
+ reset_current_user_id = true
+ end
+
+ yield
+
+ return if !reset_current_user_id
+ UserInfo.current_user_id = nil
+ end
end
diff --git a/spec/lib/user_info_spec.rb b/spec/lib/user_info_spec.rb
new file mode 100644
index 000000000..d183e9a6a
--- /dev/null
+++ b/spec/lib/user_info_spec.rb
@@ -0,0 +1,41 @@
+require 'rails_helper'
+
+RSpec.describe UserInfo do
+
+ describe '#current_user_id' do
+
+ it 'is nil by default' do
+ expect(described_class.current_user_id).to be nil
+ end
+
+ it 'takes a User ID as paramter and returns it' do
+ test_id = 99
+ described_class.current_user_id = test_id
+ expect(described_class.current_user_id).to eq(test_id)
+ end
+ end
+
+ describe '#ensure_current_user_id' do
+
+ it 'uses and keeps set User IDs' do
+ test_id = 99
+ described_class.current_user_id = test_id
+
+ described_class.ensure_current_user_id do
+ expect(described_class.current_user_id).to eq(test_id)
+ end
+
+ expect(described_class.current_user_id).to eq(test_id)
+ end
+
+ it 'sets and resets temporary User ID 1' do
+ described_class.current_user_id = nil
+
+ described_class.ensure_current_user_id do
+ expect(described_class.current_user_id).to eq(1)
+ end
+
+ expect(described_class.current_user_id).to be nil
+ end
+ end
+end
From d160a86e09c461318db1d82134823fe0129cba6b Mon Sep 17 00:00:00 2001
From: Thorsten Eckel
Date: Thu, 27 Apr 2017 11:20:57 +0200
Subject: [PATCH 04/31] Added 'Seedable' concern to (re-)seed models based on
their seed files in /db/seeds .
---
app/models/concerns/seedable.rb | 23 +++++++++++++++++++++++
app/models/overview.rb | 1 +
2 files changed, 24 insertions(+)
create mode 100644 app/models/concerns/seedable.rb
diff --git a/app/models/concerns/seedable.rb b/app/models/concerns/seedable.rb
new file mode 100644
index 000000000..8f5e79ff4
--- /dev/null
+++ b/app/models/concerns/seedable.rb
@@ -0,0 +1,23 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+module Seedable
+ extend ActiveSupport::Concern
+
+ # methods defined here are going to extend the class, not the instance of it
+ class_methods do
+
+ def reseed
+ destroy_all
+ seed
+ end
+
+ def seed
+ UserInfo.ensure_current_user_id do
+ load seedfile
+ end
+ end
+
+ def seedfile
+ "#{Rails.root}/db/seeds/#{name.pluralize.underscore}.rb"
+ end
+ end
+end
diff --git a/app/models/overview.rb b/app/models/overview.rb
index 8b4c284ce..2754d006c 100644
--- a/app/models/overview.rb
+++ b/app/models/overview.rb
@@ -3,6 +3,7 @@
class Overview < ApplicationModel
include NotifiesClients
include LatestChangeObserved
+ include Seedable
load 'overview/assets.rb'
include Overview::Assets
From 06c009255fdb6a3446b2aaf4323d6f31466774eb Mon Sep 17 00:00:00 2001
From: Rolf Schmidt
Date: Tue, 25 Apr 2017 16:04:59 +0200
Subject: [PATCH 05/31] Fixed issue #655 - Ticket were shown twice.
---
app/models/recent_view.rb | 18 ++++++++++++++----
app/models/ticket.rb | 1 +
test/unit/recent_view_test.rb | 9 ++-------
3 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/app/models/recent_view.rb b/app/models/recent_view.rb
index 19d900463..8cb226f90 100644
--- a/app/models/recent_view.rb
+++ b/app/models/recent_view.rb
@@ -2,6 +2,7 @@
class RecentView < ApplicationModel
belongs_to :object_lookup, class_name: 'ObjectLookup'
+ belongs_to :ticket, class_name: 'Ticket', foreign_key: 'o_id'
after_create :notify_clients
after_update :notify_clients
@@ -37,12 +38,21 @@ class RecentView < ApplicationModel
def self.list(user, limit = 10, type = nil)
recent_views = if !type
- RecentView.where(created_by_id: user.id)
- .order('created_at DESC, id DESC')
+ RecentView.select('o_id, recent_view_object_id, MAX(created_at) as created_at, MAX(id) as id')
+ .group(:o_id, :recent_view_object_id)
+ .where(created_by_id: user.id)
+ .limit(limit)
+ elsif type == 'Ticket'
+ state_ids = Ticket::State.by_category(:viewable_agent_new).pluck(:id)
+ RecentView.joins(:ticket)
+ .select('recent_views.o_id as o_id, recent_views.recent_view_object_id as recent_view_object_id, MAX(recent_views.created_at) as created_at, MAX(recent_views.id) as id')
+ .group(:o_id, :recent_view_object_id)
+ .where('recent_views.created_by_id = ? AND recent_views.recent_view_object_id = ? AND tickets.state_id IN (?)', user.id, ObjectLookup.by_name('Ticket'), state_ids )
.limit(limit)
else
- RecentView.select('DISTINCT(o_id), recent_view_object_id, created_at, id').where(created_by_id: user.id, recent_view_object_id: ObjectLookup.by_name(type))
- .order('created_at DESC, id DESC')
+ RecentView.select('o_id, recent_view_object_id, MAX(created_at) as created_at, MAX(id) as id')
+ .group(:o_id, :recent_view_object_id)
+ .where(created_by_id: user.id, recent_view_object_id: ObjectLookup.by_name(type))
.limit(limit)
end
diff --git a/app/models/ticket.rb b/app/models/ticket.rb
index 863338ca8..9c49b0e83 100644
--- a/app/models/ticket.rb
+++ b/app/models/ticket.rb
@@ -57,6 +57,7 @@ class Ticket < ApplicationModel
belongs_to :group, class_name: 'Group'
has_many :articles, class_name: 'Ticket::Article', after_add: :cache_update, after_remove: :cache_update
has_many :ticket_time_accounting, class_name: 'Ticket::TimeAccounting', dependent: :destroy
+ has_many :recent_views, class_name: 'RecentView', foreign_key: 'o_id', dependent: :destroy
belongs_to :organization, class_name: 'Organization'
belongs_to :state, class_name: 'Ticket::State'
belongs_to :priority, class_name: 'Ticket::Priority'
diff --git a/test/unit/recent_view_test.rb b/test/unit/recent_view_test.rb
index 610bc3596..912ca6931 100644
--- a/test/unit/recent_view_test.rb
+++ b/test/unit/recent_view_test.rb
@@ -40,14 +40,9 @@ class RecentViewTest < ActiveSupport::TestCase
assert(list[0]['o_id'], ticket1.id)
assert(list[0]['object'], 'Ticket')
- assert(list[1]['o_id'], ticket1.id)
+ assert(list[1]['o_id'], ticket2.id)
assert(list[1]['object'], 'Ticket')
-
- assert(list[2]['o_id'], ticket2.id)
- assert(list[2]['object'], 'Ticket')
-
- assert(list[3]['o_id'], ticket1.id)
- assert(list[3]['object'], 'Ticket')
+ assert_equal(2, list.count)
ticket1.destroy
ticket2.destroy
From 87ec273b5736613e82b649d66c1544e97c37eb74 Mon Sep 17 00:00:00 2001
From: Rolf Schmidt
Date: Tue, 25 Apr 2017 16:06:23 +0200
Subject: [PATCH 06/31] Fixed issue #206 - Wrong recipient on reply to Received
call.
---
.../ticket_zoom/article_view.coffee | 2 +-
.../concerns/creates_ticket_articles.rb | 1 +
.../article/fillup_from_origin_by_id.rb | 25 +++++++++++
config/application.rb | 1 +
db/migrate/20120101000010_create_ticket.rb | 1 +
db/migrate/20170421110000_add_origin_by_id.rb | 9 ++++
.../ticket_articles_controller_test.rb | 45 +++++++++++++++++++
7 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 app/models/observer/ticket/article/fillup_from_origin_by_id.rb
create mode 100644 db/migrate/20170421110000_add_origin_by_id.rb
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
index 84ffe5d2f..61f101602 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
@@ -157,7 +157,7 @@ class ArticleViewItem extends App.ObserverController
new App.WidgetAvatar(
el: @$('.js-avatar')
- object_id: article.created_by_id
+ object_id: article.origin_by_id || article.created_by_id
size: 40
)
diff --git a/app/controllers/concerns/creates_ticket_articles.rb b/app/controllers/concerns/creates_ticket_articles.rb
index 5414eb7b3..8d0e06390 100644
--- a/app/controllers/concerns/creates_ticket_articles.rb
+++ b/app/controllers/concerns/creates_ticket_articles.rb
@@ -34,6 +34,7 @@ module CreatesTicketArticles
if !current_user.permissions?('ticket.agent')
clean_params[:sender_id] = Ticket::Article::Sender.lookup(name: 'Customer').id
clean_params.delete(:sender)
+ clean_params.delete(:origin_by_id)
type = Ticket::Article::Type.lookup(id: clean_params[:type_id])
if type.name !~ /^(note|web)$/
clean_params[:type_id] = Ticket::Article::Type.lookup(name: 'note').id
diff --git a/app/models/observer/ticket/article/fillup_from_origin_by_id.rb b/app/models/observer/ticket/article/fillup_from_origin_by_id.rb
new file mode 100644
index 000000000..fa77cf3d5
--- /dev/null
+++ b/app/models/observer/ticket/article/fillup_from_origin_by_id.rb
@@ -0,0 +1,25 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+
+class Observer::Ticket::Article::FillupFromOriginById < ActiveRecord::Observer
+ observe 'ticket::_article'
+
+ def before_create(record)
+
+ # return if we run import mode
+ return if Setting.get('import_mode')
+
+ # only do fill of from if article got created via application_server (e. g. not
+ # if article and sender type is set via *.postmaster)
+ return if ApplicationHandleInfo.current.split('.')[1] == 'postmaster'
+
+ # check if origin_by_id exists
+ return if record.origin_by_id.present?
+ return if !record.ticket.customer_id
+ return if record.sender.name != 'Customer'
+ return if record.type.name != 'phone'
+
+ record.origin_by_id = record.ticket.customer_id
+ user = User.find(record.origin_by_id)
+ record.from = "#{user.firstname} #{user.lastname} <#{user.email}>"
+ end
+end
diff --git a/config/application.rb b/config/application.rb
index 32fed4b20..28aaa09c4 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -27,6 +27,7 @@ module Zammad
'observer::_ticket::_article_changes',
'observer::_ticket::_article::_fillup_from_general',
'observer::_ticket::_article::_fillup_from_email',
+ 'observer::_ticket::_article::_fillup_from_origin_by_id',
'observer::_ticket::_article::_communicate_email',
'observer::_ticket::_article::_communicate_facebook',
'observer::_ticket::_article::_communicate_twitter',
diff --git a/db/migrate/20120101000010_create_ticket.rb b/db/migrate/20120101000010_create_ticket.rb
index d9bb29bd5..6cca4ada3 100644
--- a/db/migrate/20120101000010_create_ticket.rb
+++ b/db/migrate/20120101000010_create_ticket.rb
@@ -166,6 +166,7 @@ class CreateTicket < ActiveRecord::Migration
t.column :preferences, :text, limit: 500.kilobytes + 1, null: true
t.column :updated_by_id, :integer, null: false
t.column :created_by_id, :integer, null: false
+ t.column :origin_by_id, :integer
t.timestamps limit: 3, null: false
end
add_index :ticket_articles, [:ticket_id]
diff --git a/db/migrate/20170421110000_add_origin_by_id.rb b/db/migrate/20170421110000_add_origin_by_id.rb
new file mode 100644
index 000000000..72887d8c6
--- /dev/null
+++ b/db/migrate/20170421110000_add_origin_by_id.rb
@@ -0,0 +1,9 @@
+class AddOriginById < ActiveRecord::Migration
+ def up
+
+ # return if it's a new setup
+ return if !Setting.find_by(name: 'system_init_done')
+
+ add_column :ticket_articles, :origin_by_id, :integer
+ end
+end
diff --git a/test/controllers/ticket_articles_controller_test.rb b/test/controllers/ticket_articles_controller_test.rb
index b32ed6120..78c054446 100644
--- a/test/controllers/ticket_articles_controller_test.rb
+++ b/test/controllers/ticket_articles_controller_test.rb
@@ -280,4 +280,49 @@ AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
end
+ test '03.01 create phone ticket for customer and expected origin_by_id' do
+ credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
+
+ params = {
+ title: 'a new ticket #1',
+ group: 'Users',
+ customer_id: @customer_without_org.id,
+ article: {
+ body: 'some body',
+ sender: 'Customer',
+ type: 'phone',
+ }
+ }
+ post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
+ assert_response(201)
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+
+ article = Ticket::Article.find_by( ticket_id: result['id'] )
+ assert_equal(@customer_without_org.id, article.origin_by_id)
+ assert_equal('Tickets Customer1 ', article.from)
+ end
+
+ test '03.02 create phone ticket by customer and manipulate origin_by_id' do
+ credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-customer1@example.com', 'customer1pw')
+
+ params = {
+ title: 'a new ticket #1',
+ group: 'Users',
+ customer_id: @customer_without_org.id,
+ article: {
+ body: 'some body',
+ sender: 'Customer',
+ type: 'phone',
+ origin_by_id: 1,
+ }
+ }
+ post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
+ assert_response(201)
+ result = JSON.parse(@response.body)
+ assert_equal(Hash, result.class)
+
+ article = Ticket::Article.find_by( ticket_id: result['id'] )
+ assert_nil(article.origin_by_id)
+ end
end
From 0a6cd3897e260618be73b608eae7e331644ea7b4 Mon Sep 17 00:00:00 2001
From: Rolf Schmidt
Date: Tue, 25 Apr 2017 16:10:38 +0200
Subject: [PATCH 07/31] Fixed issue #655 - Ticket were shown twice.
---
app/models/ticket.rb | 1 -
1 file changed, 1 deletion(-)
diff --git a/app/models/ticket.rb b/app/models/ticket.rb
index 9c49b0e83..863338ca8 100644
--- a/app/models/ticket.rb
+++ b/app/models/ticket.rb
@@ -57,7 +57,6 @@ class Ticket < ApplicationModel
belongs_to :group, class_name: 'Group'
has_many :articles, class_name: 'Ticket::Article', after_add: :cache_update, after_remove: :cache_update
has_many :ticket_time_accounting, class_name: 'Ticket::TimeAccounting', dependent: :destroy
- has_many :recent_views, class_name: 'RecentView', foreign_key: 'o_id', dependent: :destroy
belongs_to :organization, class_name: 'Organization'
belongs_to :state, class_name: 'Ticket::State'
belongs_to :priority, class_name: 'Ticket::Priority'
From 34293909dd3f6c533217914034bcbe7373941adb Mon Sep 17 00:00:00 2001
From: Rolf Schmidt
Date: Tue, 25 Apr 2017 16:19:07 +0200
Subject: [PATCH 08/31] Fixed issue #187 - Wrong article order after merging of
tickets.
---
.../ticket_zoom/article_view.coffee | 30 +++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
index 61f101602..3d7e15a54 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
@@ -10,7 +10,7 @@ class App.TicketZoomArticleView extends App.Controller
run: =>
all = []
- for ticket_article_id in @ticket_article_ids
+ for ticket_article_id, index in @ticket_article_ids
controllerKey = ticket_article_id.toString()
if !@articleController[controllerKey]
el = $('')
@@ -21,7 +21,8 @@ class App.TicketZoomArticleView extends App.Controller
ui: @ui
highligher: @highligher
)
- all.push el
+ if !@ticketArticleInsertByIndex(index, el)
+ all.push el
@el.append(all)
# check elements to remove
@@ -34,6 +35,31 @@ class App.TicketZoomArticleView extends App.Controller
controller.remove()
delete @articleController[article_id.toString()]
+ ticketArticleInsertByIndex: (elIndex, el) =>
+ return false if !@$('.ticket-article-item').length
+
+ # in case of a merge it can happen that there are already
+ # articles rendered in the ticket, but the new article need
+ # to be inserted at the correct position in the the ticket
+ for index in [elIndex .. 0]
+ article_id = @ticket_article_ids[index]
+ continue if !article_id
+ article = @$(".ticket-article-item[data-id=#{article_id}]")
+ continue if !article.length
+ article.after(el)
+ return true
+
+ for index in [elIndex .. @ticket_article_ids.length - 1]
+ article_id = @ticket_article_ids[index]
+ continue if !article_id
+ article = @$(".ticket-article-item[data-id=#{article_id}]")
+ continue if !article.length
+ article.before(el)
+ return true
+
+ false
+
+
class ArticleViewItem extends App.ObserverController
model: 'TicketArticle'
observe:
From 3ec2ce60381ac0e01720e9cea3c16721f193bf5e Mon Sep 17 00:00:00 2001
From: Gilson
Date: Tue, 25 Apr 2017 14:52:04 -0300
Subject: [PATCH 09/31] Localization on templates (#993)
* Mailer resource translated for Portuguese Brazilian language
* Portuguese Brazilian email template localization
---
.../mailer/password_change/pt-br.html.erb | 9 ++++++
.../mailer/password_reset/pt-br.html.erb | 15 ++++++++++
app/views/mailer/signup/pt-br.html.erb | 9 ++++++
app/views/mailer/test_ticket/pt-br.html.erb | 9 ++++++
app/views/mailer/ticket_create/pt-br.html.erb | 24 +++++++++++++++
.../mailer/ticket_escalation/pt-br.html.erb | 18 ++++++++++++
.../ticket_escalation_warning/pt-br.html.erb | 19 ++++++++++++
.../ticket_reminder_reached/pt-br.html.erb | 18 ++++++++++++
app/views/mailer/ticket_update/pt-br.html.erb | 29 +++++++++++++++++++
.../mailer/user_device_new/pt-br.html.erb | 19 ++++++++++++
.../user_device_new_location/pt-br.html.erb | 20 +++++++++++++
app/views/mailer/user_invite/pt-br.erb | 13 +++++++++
app/views/slack/ticket_create/pt-br.md.erb | 9 ++++++
.../slack/ticket_escalation/pt-br.md.erb | 7 +++++
.../ticket_escalation_warning/pt-br.md.erb | 7 +++++
.../ticket_reminder_reached/pt-br.md.erb | 7 +++++
app/views/slack/ticket_update/pt-br.md.erb | 11 +++++++
17 files changed, 243 insertions(+)
create mode 100644 app/views/mailer/password_change/pt-br.html.erb
create mode 100644 app/views/mailer/password_reset/pt-br.html.erb
create mode 100644 app/views/mailer/signup/pt-br.html.erb
create mode 100644 app/views/mailer/test_ticket/pt-br.html.erb
create mode 100644 app/views/mailer/ticket_create/pt-br.html.erb
create mode 100644 app/views/mailer/ticket_escalation/pt-br.html.erb
create mode 100644 app/views/mailer/ticket_escalation_warning/pt-br.html.erb
create mode 100644 app/views/mailer/ticket_reminder_reached/pt-br.html.erb
create mode 100644 app/views/mailer/ticket_update/pt-br.html.erb
create mode 100644 app/views/mailer/user_device_new/pt-br.html.erb
create mode 100644 app/views/mailer/user_device_new_location/pt-br.html.erb
create mode 100644 app/views/mailer/user_invite/pt-br.erb
create mode 100644 app/views/slack/ticket_create/pt-br.md.erb
create mode 100644 app/views/slack/ticket_escalation/pt-br.md.erb
create mode 100644 app/views/slack/ticket_escalation_warning/pt-br.md.erb
create mode 100644 app/views/slack/ticket_reminder_reached/pt-br.md.erb
create mode 100644 app/views/slack/ticket_update/pt-br.md.erb
diff --git a/app/views/mailer/password_change/pt-br.html.erb b/app/views/mailer/password_change/pt-br.html.erb
new file mode 100644
index 000000000..eab7701e4
--- /dev/null
+++ b/app/views/mailer/password_change/pt-br.html.erb
@@ -0,0 +1,9 @@
+Sua senha #{config.product_name} foi alterada
+
+Oi #{user.firstname},
+
+A senha para a sua conta #{config.product_name} #{user.login} foi alterada recentemente.
+
+Esta atividade não é conhecida por você ? Caso não, entre em contato com o administrador do sistema.
+
+Time #{config.product_name}
diff --git a/app/views/mailer/password_reset/pt-br.html.erb b/app/views/mailer/password_reset/pt-br.html.erb
new file mode 100644
index 000000000..66c662505
--- /dev/null
+++ b/app/views/mailer/password_reset/pt-br.html.erb
@@ -0,0 +1,15 @@
+Resetando sua senha #{config.product_name}
+
+Oi #{user.firstname},
+
+Nós recebemos uma requisição para resetar a senha da sua conta #{config.product_name}, #{user.login}.
+
+Se você deseja alterar sua senha, clique no link a seguir (ou copie e cole esta URL no seu navegador):
+
+
+
+Este link vai te levar até a página onde você poderá alterar sua senha.
+
+Se você não desejar resetar sua senha, por favor ignore esta mensagem. Sua senha não vai ser resetada.
+
+Time #{config.product_name}
diff --git a/app/views/mailer/signup/pt-br.html.erb b/app/views/mailer/signup/pt-br.html.erb
new file mode 100644
index 000000000..3e436f8e4
--- /dev/null
+++ b/app/views/mailer/signup/pt-br.html.erb
@@ -0,0 +1,9 @@
+Confirme sua conta #{config.product_name}, #{user.firstname} #{user.lastname}
+
+Oi #{user.firstname},
+
+Confirme seu email para completar o cadastro de sua conta #{config.product_name}. Isto é fácil, basta clicar no link a seguir.
+
+
+
+Time #{config.product_name}
diff --git a/app/views/mailer/test_ticket/pt-br.html.erb b/app/views/mailer/test_ticket/pt-br.html.erb
new file mode 100644
index 000000000..44cffd1e8
--- /dev/null
+++ b/app/views/mailer/test_ticket/pt-br.html.erb
@@ -0,0 +1,9 @@
+Teste de chamado!
+
+Prezado #{agent.firstname},
+
+Este é um chamado de teste. Eu sou um usuário e preciso de ajuda ! :)
+
+#{customer.fullname}
+
+O projeto Zammad
diff --git a/app/views/mailer/ticket_create/pt-br.html.erb b/app/views/mailer/ticket_create/pt-br.html.erb
new file mode 100644
index 000000000..bd605b089
--- /dev/null
+++ b/app/views/mailer/ticket_create/pt-br.html.erb
@@ -0,0 +1,24 @@
+Novo Chamado (#{ticket.title})
+
+Oi #{recipient.firstname},
+
+Um novo chamado (#{ticket.title}) foi criado por "#{current_user.longname}".
+
+
+#{t('Group')}: #{ticket.group.name}
+#{t('Owner')}: #{ticket.owner.fullname}
+#{t('State')}: #{t(ticket.state.name)}
+
+
+<% if @objects[:article] %>
+
+ #{t('Information')}:
+
+ #{article.body_as_html}
+
+
+<% end %>
+
+
diff --git a/app/views/mailer/ticket_escalation/pt-br.html.erb b/app/views/mailer/ticket_escalation/pt-br.html.erb
new file mode 100644
index 000000000..dedd79a3b
--- /dev/null
+++ b/app/views/mailer/ticket_escalation/pt-br.html.erb
@@ -0,0 +1,18 @@
+Chamado escalado (#{ticket.title})
+
+Oi #{recipient.firstname},
+
+Um chamado (#{ticket.title}) de "#{ticket.customer.longname}" foi escalado desde "#{ticket.escalation_at}"!
+
+<% if @objects[:article] %>
+
+ #{t('Information')}:
+
+ #{article.body_as_html}
+
+
+<% end %>
+
+
diff --git a/app/views/mailer/ticket_escalation_warning/pt-br.html.erb b/app/views/mailer/ticket_escalation_warning/pt-br.html.erb
new file mode 100644
index 000000000..2e461e44f
--- /dev/null
+++ b/app/views/mailer/ticket_escalation_warning/pt-br.html.erb
@@ -0,0 +1,19 @@
+O Chamado vai ser escalado (#{ticket.title})
+
+
+Oi #{recipient.firstname},
+
+Um chamado (#{ticket.title}) de "#{ticket.customer.longname}" vai ser escalado em "#{ticket.escalation_at}"!
+
+<% if @objects[:article] %>
+
+ #{t('Information')}:
+
+ #{article.body_as_html}
+
+
+<% end %>
+
+
diff --git a/app/views/mailer/ticket_reminder_reached/pt-br.html.erb b/app/views/mailer/ticket_reminder_reached/pt-br.html.erb
new file mode 100644
index 000000000..7be814f2d
--- /dev/null
+++ b/app/views/mailer/ticket_reminder_reached/pt-br.html.erb
@@ -0,0 +1,18 @@
+Lembrete (#{ticket.title})
+
+Oi #{recipient.firstname},
+
+Um chamado precisa de atenção, um lembrete foi criado (#{ticket.title}) com o usuário "#{ticket.customer.longname}".
+
+<% if @objects[:article] %>
+
+ #{t('Information')}:
+
+ #{article.body_as_html}
+
+
+<% end %>
+
+
diff --git a/app/views/mailer/ticket_update/pt-br.html.erb b/app/views/mailer/ticket_update/pt-br.html.erb
new file mode 100644
index 000000000..5e17974e4
--- /dev/null
+++ b/app/views/mailer/ticket_update/pt-br.html.erb
@@ -0,0 +1,29 @@
+Chamado atualizado (#{ticket.title})
+
+Oi #{recipient.firstname},
+
+
+O chamado (#{ticket.title}) foi atualizado por "#{current_user.longname}".
+
+
+<% if @objects[:changes] && !@objects[:changes].empty? %>
+
+ #{t('Changes')}:
+ <% @objects[:changes].each do |key, value| %>
+ <%= t key %>: <%= h value[0] %> -> <%= h value[1] %>
+ <% end %>
+
+<% end %>
+
+<% if @objects[:article] %>
+
+ #{t('Information')}:
+
+ #{article.body_as_html}
+
+
+<% end %>
+
+
diff --git a/app/views/mailer/user_device_new/pt-br.html.erb b/app/views/mailer/user_device_new/pt-br.html.erb
new file mode 100644
index 000000000..6fe4ad95f
--- /dev/null
+++ b/app/views/mailer/user_device_new/pt-br.html.erb
@@ -0,0 +1,19 @@
+#{config.product_name} login detectado em um novo dispositivo
+
+Oi #{user.firstname},
+
+Isto é como se você tivesse logado com sua conta usando um novo dispositivo em "#{user_device.created_at}":
+
+
+Seu dispositivo: #{user_device.name}
+Sua localização (relativa): #{user_device.location}
+Seu IP: #{user_device.ip}
+
+
+Seu dispositivo foi adicionado na lista de dispositivos conhecidos, qual você pode ver aqui:
+
+#{config.http_type}://#{config.fqdn}/#profile/devices
+
+Se não foi você, remova o dispositivo, altere sua senha e entre em contato com o Administrador. Alguém pode ter ganho acesso não autorizado à sua conta.
+
+Time #{config.product_name}
diff --git a/app/views/mailer/user_device_new_location/pt-br.html.erb b/app/views/mailer/user_device_new_location/pt-br.html.erb
new file mode 100644
index 000000000..ae1076d34
--- /dev/null
+++ b/app/views/mailer/user_device_new_location/pt-br.html.erb
@@ -0,0 +1,20 @@
+#{config.product_name} login detectado em um novo País
+
+Oi #{user.firstname},
+
+Isto é como se você tivesse usado sua conta com um dispositivo conhecido, porém, de um outro país em "#{user_device.created_at}":
+
+
+Seu dispositivo: #{user_device.name}
+Sua localização (relativa): #{user_device.location}
+Seu IP: #{user_device.ip}
+
+
+O País foi adicionado na sua lista de dispositivos conhecidos, que pode ser visto aqui:
+
+#{config.http_type}://#{config.fqdn}/#profile/devices
+
+If this wasn't you, remove the device, changing your account password, and contacting your administrator. Somebody might have gained unauthorized access to your account.
+Se não foi você, remova o dispositivo, altere sua senha e entre em contato com o Administrador. Alguém pode ter ganho acesso não autorizado à sua conta.
+
+Your #{config.product_name} Team
diff --git a/app/views/mailer/user_invite/pt-br.erb b/app/views/mailer/user_invite/pt-br.erb
new file mode 100644
index 000000000..8fdfb6d4d
--- /dev/null
+++ b/app/views/mailer/user_invite/pt-br.erb
@@ -0,0 +1,13 @@
+Convite para #{config.product_name} em #{config.fqdn}
+
+Oi #{user.firstname},
+
+Eu (#{current_user.firstname} #{current_user.lastname}) estou te convidando para #{config.product_name} - nosso suporte ao usuário / plataforma de chamados.
+
+Clique
aqui e crie sua senha.
+
+Divirta-se,
+
+#{current_user.firstname} #{current_user.lastname}
+
+Time #{config.product_name}
diff --git a/app/views/slack/ticket_create/pt-br.md.erb b/app/views/slack/ticket_create/pt-br.md.erb
new file mode 100644
index 000000000..863ee2ad6
--- /dev/null
+++ b/app/views/slack/ticket_create/pt-br.md.erb
@@ -0,0 +1,9 @@
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Criado por #{current_user.longname} em #{ticket.updated_at}_
+* #{t('Group')}: #{ticket.group.name}
+* #{t('Owner')}: #{ticket.owner.fullname}
+* #{t('State')}: #{t(ticket.state.name)}
+
+<% if @objects[:article] %>
+#{article.body_as_text}
+<% end %>
diff --git a/app/views/slack/ticket_escalation/pt-br.md.erb b/app/views/slack/ticket_escalation/pt-br.md.erb
new file mode 100644
index 000000000..2e88e2f54
--- /dev/null
+++ b/app/views/slack/ticket_escalation/pt-br.md.erb
@@ -0,0 +1,7 @@
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Escalado em #{ticket.escalation_at}_
+Um chamado (#{ticket.title}) de "#{ticket.customer.longname}" foi escalado desde "#{ticket.escalation_at}"!
+
+<% if @objects[:article] %>
+#{article.body_as_text}
+<% end %>
diff --git a/app/views/slack/ticket_escalation_warning/pt-br.md.erb b/app/views/slack/ticket_escalation_warning/pt-br.md.erb
new file mode 100644
index 000000000..04a63835b
--- /dev/null
+++ b/app/views/slack/ticket_escalation_warning/pt-br.md.erb
@@ -0,0 +1,7 @@
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Vai ser escalado em #{ticket.escalation_at}_
+Um chamado (#{ticket.title}) de "#{ticket.customer.longname}" vai ser escalado em "#{ticket.escalation_at}"!
+
+<% if @objects[:article] %>
+#{article.body_as_text}
+<% end %>
diff --git a/app/views/slack/ticket_reminder_reached/pt-br.md.erb b/app/views/slack/ticket_reminder_reached/pt-br.md.erb
new file mode 100644
index 000000000..1fcb9561e
--- /dev/null
+++ b/app/views/slack/ticket_reminder_reached/pt-br.md.erb
@@ -0,0 +1,7 @@
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Lembrete!_
+um chamado precisa de atenção, lembrete criado para (#{ticket.title}) com usuário "*#{ticket.customer.longname}*".
+
+<% if @objects[:article] %>
+#{article.body_as_text}
+<% end %>
diff --git a/app/views/slack/ticket_update/pt-br.md.erb b/app/views/slack/ticket_update/pt-br.md.erb
new file mode 100644
index 000000000..f6fb6a046
--- /dev/null
+++ b/app/views/slack/ticket_update/pt-br.md.erb
@@ -0,0 +1,11 @@
+# #{ticket.title}
+_<#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}|Ticket##{ticket.number}>: Atualizado por #{current_user.longname} em #{ticket.updated_at}_
+<% if @objects[:changes] && !@objects[:changes].empty? %>
+ <% @objects[:changes].each do |key, value| %>
+ * <%= t key %>: <%= h value[0] %> -> <%= h value[1] %>
+ <% end %>
+<% end %>
+
+<% if @objects[:article] %>
+#{article.body_as_text}
+<% end %>
From fedd9fb08795b6ce5b267863a0085aad90ff0591 Mon Sep 17 00:00:00 2001
From: chrisdecker1201
Date: Tue, 25 Apr 2017 20:45:35 +0200
Subject: [PATCH 10/31] hidden form on small screen/smartphone (#977)
---
public/assets/form/form.css | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/public/assets/form/form.css b/public/assets/form/form.css
index 28b8fd64f..e503b82ed 100644
--- a/public/assets/form/form.css
+++ b/public/assets/form/form.css
@@ -59,7 +59,8 @@
background: white;
border-radius: 5px;
padding: 24px 24px 22px;
- width: 26em;
+ width: 90%;
+ max-width: 26em;
margin: 0 auto;
box-sizing: border-box;
position: relative;
From ee31cd1bdd61b4204bec7e34bd2f0dc924306a77 Mon Sep 17 00:00:00 2001
From: Martin Edenhofer
Date: Tue, 25 Apr 2017 20:51:23 +0200
Subject: [PATCH 11/31] Updated gems as in issue #805 suggested.
---
Gemfile.lock | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 3415b4677..5793063e7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -46,7 +46,7 @@ GEM
tzinfo (~> 1.1)
addressable (2.4.0)
arel (6.0.3)
- argon2 (1.1.1)
+ argon2 (1.1.3)
ffi (~> 1.9)
ffi-compiler (~> 0.1)
ast (2.3.0)
@@ -110,7 +110,7 @@ GEM
dnsruby (>= 1.5)
equalizer (0.0.10)
erubis (2.7.0)
- eventmachine (1.2.0.1)
+ eventmachine (1.2.3)
execjs (2.7.0)
factory_girl (4.8.0)
activesupport (>= 3.0.0)
@@ -121,7 +121,7 @@ GEM
multipart-post (>= 1.2, < 3)
faraday-http-cache (1.3.1)
faraday (~> 0.8)
- ffi (1.9.14)
+ ffi (1.9.18)
ffi-compiler (0.1.3)
ffi (>= 1.0.0)
rake
@@ -248,7 +248,7 @@ GEM
omniauth-oauth (~> 1.1)
parser (2.3.1.2)
ast (~> 2.2)
- pg (0.18.4)
+ pg (0.20.0)
pluginator (1.3.0)
power_assert (0.3.1)
powerpack (0.1.1)
@@ -292,7 +292,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rainbow (2.1.0)
raindrops (0.17.0)
- rake (11.2.2)
+ rake (12.0.0)
rb-fsevent (0.9.7)
rb-inotify (0.9.7)
ffi (>= 0.5.0)
From e122bd9935ad63c875bc5cdf44a47d9907eb015e Mon Sep 17 00:00:00 2001
From: Martin Edenhofer
Date: Wed, 26 Apr 2017 01:43:05 +0200
Subject: [PATCH 12/31] Moved back to pg 0.18.4 (newer versions are not working
correctly).
---
Gemfile.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 5793063e7..4efc085b7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -248,7 +248,7 @@ GEM
omniauth-oauth (~> 1.1)
parser (2.3.1.2)
ast (~> 2.2)
- pg (0.20.0)
+ pg (0.18.4)
pluginator (1.3.0)
power_assert (0.3.1)
powerpack (0.1.1)
From c0afd44e0b002d4191c6e1ea164401345d2cac4d Mon Sep 17 00:00:00 2001
From: Martin Edenhofer
Date: Wed, 26 Apr 2017 08:38:46 +0200
Subject: [PATCH 13/31] Fixed html sanitizer loop. Extended tests.
---
app/models/channel/filter/identify_sender.rb | 21 +-
lib/html_sanitizer.rb | 21 +-
test/fixtures/mail49.box | 2282 ++++++++++++++++++
test/unit/aaa_string_test.rb | 11 +-
test/unit/email_parser_test.rb | 6 +-
test/unit/email_process_test.rb | 25 +
test/unit/html_sanitizer_test.rb | 9 +-
test/unit/user_test.rb | 19 +-
8 files changed, 2358 insertions(+), 36 deletions(-)
create mode 100644 test/fixtures/mail49.box
diff --git a/app/models/channel/filter/identify_sender.rb b/app/models/channel/filter/identify_sender.rb
index db2c51b31..38c88aed3 100644
--- a/app/models/channel/filter/identify_sender.rb
+++ b/app/models/channel/filter/identify_sender.rb
@@ -126,8 +126,6 @@ module Channel::Filter::IdentifySender
end
def self.user_create(data)
-
- # return existing
user = User.find_by(email: data[:email].downcase)
if !user
user = User.find_by(login: data[:email].downcase)
@@ -137,10 +135,7 @@ module Channel::Filter::IdentifySender
if user
if user.firstname.blank? && user.lastname.blank?
if data[:firstname].present?
- data[:firstname].strip!
- data[:firstname].delete!('"')
- data[:firstname].gsub!(/^'/, '')
- data[:firstname].gsub!(/'$/, '')
+ data[:firstname] = cleanup_name(data[:firstname])
user.update_attributes(
firstname: data[:firstname]
)
@@ -157,10 +152,7 @@ module Channel::Filter::IdentifySender
if data[item.to_sym].nil?
data[item.to_sym] = ''
end
- data[item.to_sym].strip!
- data[item.to_sym].delete!('"')
- data[item.to_sym].gsub!(/^'/, '')
- data[item.to_sym].gsub!(/'$/, '')
+ data[item.to_sym] = cleanup_name(data[item.to_sym])
}
data[:password] = ''
data[:active] = true
@@ -176,4 +168,13 @@ module Channel::Filter::IdentifySender
user
end
+ def self.cleanup_name(string)
+ string.strip!
+ string.delete!('"')
+ string.gsub!(/^'/, '')
+ string.gsub!(/'$/, '')
+ string.gsub!(/.+?\s\(.+?\)$/, '')
+ string
+ end
+
end
diff --git a/lib/html_sanitizer.rb b/lib/html_sanitizer.rb
index 415401727..e3e3cf7df 100644
--- a/lib/html_sanitizer.rb
+++ b/lib/html_sanitizer.rb
@@ -38,7 +38,7 @@ satinize html string based on whiltelist
# replace tags, keep subtree
if !tags_whitelist.include?(node.name)
- node.replace strict(node.children.to_s)
+ node.replace node.children.to_s
Loofah::Scrubber::STOP
end
@@ -132,7 +132,7 @@ satinize html string based on whiltelist
# prepare links
if node['href']
href = cleanup_target(node['href'])
- if external && !href.downcase.start_with?('//') && href.downcase !~ %r{^.{1,6}://.+?}
+ if external && href.present? && !href.downcase.start_with?('//') && href.downcase !~ %r{^.{1,6}://.+?}
node['href'] = "http://#{node['href']}"
href = node['href']
end
@@ -145,9 +145,9 @@ satinize html string based on whiltelist
# check if href is different to text
if external && node.name == 'a' && !url_same?(node['href'], node.text)
if node['href'].blank?
- node.replace strict(node.children.to_s)
+ node.replace node.children.to_s
Loofah::Scrubber::STOP
- elsif node.children.empty? || node.children.first.class == Nokogiri::XML::Text
+ elsif (node.children.empty? || node.children.first.class == Nokogiri::XML::Text) && node.text.present?
text = Nokogiri::XML::Text.new("#{node['href']} (", node.document)
node.add_previous_sibling(text)
node['href'] = cleanup_target(node.text)
@@ -178,7 +178,17 @@ satinize html string based on whiltelist
end
end
- Loofah.fragment(string).scrub!(scrubber).to_s
+
+ new_string = ''
+ done = true
+ while done
+ new_string = Loofah.fragment(string).scrub!(scrubber).to_s
+ if string == new_string
+ done = false
+ end
+ string = new_string
+ end
+ string
end
=begin
@@ -253,7 +263,6 @@ cleanup html string:
Loofah::Scrubber::STOP
end
end
- string = Loofah.fragment(string).scrub!(scrubber_structure).to_s
new_string = ''
done = true
diff --git a/test/fixtures/mail49.box b/test/fixtures/mail49.box
new file mode 100644
index 000000000..4052c6e6f
--- /dev/null
+++ b/test/fixtures/mail49.box
@@ -0,0 +1,2282 @@
+Return-Path:
+Received: from deli01.example.de (deli01.vpn.example.de [10.5.2.22])
+ by mail14b (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA;
+ Thu, 20 Apr 2017 13:20:02 +0200
+X-Sieve: CMU Sieve 2.2
+Received: from asuran.example.de (ld-ipx3-2.vpn.example.de [10.5.0.29])
+ by deli01.example.de (Postfix) with ESMTP id 281E71B39
+ for ; Thu, 20 Apr 2017 13:20:02 +0200 (CEST)
+Received: from exspamix-01.example.de (exspamix-01.example.de [10.0.106.132])
+ by asuran.example.de (Postfix) with ESMTP id 212F721F74
+ for ; Thu, 20 Apr 2017 13:20:02 +0200 (CEST)
+Received: from mail1.bemta6.example.com ([10.0.254.115])
+ by exspamix-01.example.de with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256)
+ (Exim 4.86)
+ (envelope-from )
+ id 1d1A7y-0003Ft-4c
+ for info@example.de; Thu, 20 Apr 2017 13:20:02 +0200
+Received: from [10.0.143.35] by server-11.bemta-6.example.com id 9D/56-03587-D5998F85; Thu, 20 Apr 2017 11:19:57 +0000
+X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrBIsWRWlGSWpSXmKPExsUScfONjm7MzB8
+ RBktWSVp8fXCJyYHRo3HZDqYAxijWzLyk/IoE1ozGZTsZC77NNKxY+HwlYwPjrn0GXYycHEIC
+ axgllu0v7mLkArI3M0qsWd7LCJJgE7CXeHF5ImsXIweHsEC+RN+fKpCwiICExNLpd5lAbGYBH
+ 4l5hxezgdi8AoISJ2c+YYGYqS6x+MJ5sDiLgKrE/z99zBA1FhKHJp9lBhkpJKAhMflJCogpIW
+ At0XytdgIjzywkQ2chGQoR15BonTOXHcLWlli28DUzhJ0usWXxRChbUWJK90OgGg4gO1fi+xN
+ OiLC7xPO5x9lQlYDYQRLTXnUyLWDkWsWoUZxaVJZapGtorJdUlJmeUZKbmJmja2hgppebWlyc
+ mJ6ak5hUrJecn7uJERjiDECwg/HLsoBDjJIcTEqivB9df0QI8SXlp1RmJBZnxBeV5qQWH2KU4
+ eBQkuANnwGUEyxKTU+tSMvMAUYbTFqCg0dJhLcHJM1bXJCYW5yZDpE6xagoJc4bC5IQAElklO
+ bBtcEi/BKjrJQwLyPQIUI8BalFuZklqPKvGMU5GJWEeeNBpvBk5pXATX8FtJgJaPFZP7DFJYk
+ IKakGRoOlPMxeV//ueXquzVgi8NPr53ISdt0FxlP/74z86rrs2ocDfy0mXFVl/JGm+P785cJt
+ m3Z/f6TDw6r7iEF/2b/6fSZdNfNXKWvHLXN8/M37wXPbuLmF/oz1+bv6ZGXfb/aubzzad/e9V
+ tL6E+sPFNy9af+e4cK1k8tmbtWda3o1VsfA+tm5wmlKLMUZiYZazEXFiQBjjaIj6wIAAA==
+X-Env-Sender: marcus.smith@example.com
+X-Msg-Ref: server-8.tower-21.example.com!1492686707!64387300!16
+X-Originating-IP: [10.0.236.44]
+X-StarScan-Received:
+X-StarScan-Version: 9.4.12; banners=-,-,-
+X-VirusChecked: Checked
+Received: (qmail 15951 invoked from network); 20 Apr 2017 11:19:31 -0000
+Received: from mail.example.de (HELO mail.example.de) (10.0.236.44)
+ by server-8.tower-21.example.com with AES256-SHA encrypted SMTP; 20 Apr 2017 11:19:31 -0000
+Received: from desfsrvv002.fsm.local (10.0.0.8) by desfsrvv002.fsm.local
+ (192.168.0.8) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Thu, 20 Apr
+ 2017 13:07:26 +0200
+Received: from desfcl013 (10.0.0.104) by desfsrvv002.fsm.local
+ (192.168.0.8) with Microsoft SMTP Server id 15.0.1210.3 via Frontend
+ Transport; Thu, 20 Apr 2017 13:07:26 +0200
+From: "Marcus Smith (ABC)"
+Subject: Kinderschwimmbrille ABC Little Twist: Schnell angelegt, keine
+ verhedderten Haare (Pressemitteilung)
+To:
+Content-Type: multipart/mixed; boundary="sp9pxLEwghDaJRixlkdZ=_QAHPr6hfigLP"
+MIME-Version: 1.0
+Reply-To:
+Date: Thu, 20 Apr 2017 13:03:16 +0200
+Message-ID: <2017042013031651F46156FA$3429A82563@DESFCL>
+X-EXCLAIMER-MD-CONFIG: 86773a0c-e9fa-4f6d-a02b-c46649ddaf4c
+X-SpamExperts-Class: unsure
+X-SpamExperts-Evidence: Combined (0.80)
+X-Recommended-Action: accept
+X-Filter-ID: s0sct1PQhAABKnZB5plbIScDS1Ah3IN6DXwtbFNCAl9CZDDZypSCW3NVr3i3Oj550hNw506ok7Oc
+ h2zx/8fhdRQ0A3zDD8BaOB3G1ogsOIB6Qy28/iROdjfah1Vpm5PuPzFrK7tpZ0ITrq1CoGNVtju+
+ l0kwMLVeJoOItqLgg2uAFIbyFgFecVFv/oAIeL162Fb/cqhFAxVBJGOP0Pl+MEXDm9fFn8RsoOjp
+ uruGGJv+TcyVhp/anhUQXQAtT82HGlugeeYNRP+TKatltgBEa53+nQWdNbMeBvr5xRuZ2g/ubpln
+ biDyBMUiEvUZuPnVLR/VPgh4XHQAxXzmObDIwIrVOdzGaC+THNCruH7JDih+pvlHhV6a5QjptwQB
+ GybQPE9+Sr8BITYHkTKhGWcEQstt8iMtuGwXXAwQbE6xuMJ0xYCHwzEoZpUBagq+YQPMQF0hsKSx
+ nP2Z7odzKCKStLBgqqhRRUPmBDlwgPURU+G20RdCfgC+oEUcBXLctP0RktTJIr248aS6veEqJg1E
+ dcwVEwkykH0Q3JVVoWHY8Dbqipq1Cj9QD+bzSr3gFny7o9soYkGbHBPnsIda/J414Ihhr8wUfd3z
+ tLcZN92tbpkPOmJ39LtFIA6XeJo+eLpxHaSF/L0D9WqxmMcGz0S2BNpYFKH/ASE5b9LmZe/hwXj0
+ FqjTwPjMRY/JqJtendI1UmT5bb00m8M1jZ5Apm7ze27Pd61rzx0VcEbaWfsImrpVLnrBpxHdPacY
+ TU723PojdqkmsUMOz1zNvAzvj7OyhzBsPQTf4dzhoDwLospP/sE=
+X-Report-Abuse-To: spam@exspamix-01.example.de
+
+--sp9pxLEwghDaJRixlkdZ=_QAHPr6hfigLP
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+
+
+
+
+ Kinderschwimmbrille 1=
+ABCD=20
+Little Twist: Schnell angelegt, keine verhedderten Haare=20
+(Pressemitteilung)
+
+
+=E2=97=8F durchdachtes Kopfband f=C3=BCr schnelles & einfaches Anlegen=
+ =E2=97=8F die fr=C3=B6hliche=20
+& farbenfrohe Gestaltung freut Kinder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=20
+Sehr geehrte Frau Smith,
+
+die Kinderschwimmbrille ABC Li=
+ttle=20
+Twist ist
der neue Star im Kinderbecken: Das durchdachte
Kopfb=
+and=20
+macht es Eltern und Lehrern einfach,
ihren Sch=C3=BCtzlingen die=20=
+
+Schwimmbrille anzulegen
und anzupassen. Die farbenfrohe Gestaltung =
+in=20
+
blau und pink mit dem Motiv der beliebten Robbe
ABC erfreut =
+die=20
+Kinder und bringt Spa=C3=9F ins
Becken.
<<< alle Info siehe angeh=C3=A4ngte=20
+ PDF>>>
Den=20
+Schwimmexperten von ABC ist aufgefallen,
dass Eltern wie auch=20=
+
+Schwimmlehrer oft viel Zeit
ben=C3=B6tigen, um ihren Kindern oder =
+Sch=C3=BClern=20
+die
Schwimmbrillen anzulegen und zu justieren. Oft
m=C3=BCssen=
+ die=20
+Kids dazu eigens aus dem Wasser
geholt werden. Manche Kopfb=C3=A4n=
+der=20
+verheddern
sich zudem gerne in den Haaren, was zu Ziepen
und=20=
+
+letztendlich zu Tr=C3=A4nen f=C3=BChrt.
F=C3=BCr die ABC Little Twist wurde daher ein sehr
einf=
+acher=20
+Verstellmechanismus am Kopfband ent-
wickelt. Das Verstellen ist=20=
+
+m=C3=B6glich, ohne, dass die
Schwimmbrille abgesetzt werden muss. =
+Die Zeit=20
+
im Wasser wird nicht unterbrochen, der Flow wird
nicht gest=C3=
+=B6rt=20
+und das Vertrauen zum Wasser muss
nicht neu aufgebaut werden.=20
+Resultat: Die Kinder
haben mehr Spa=C3=9F im Becken.=
+
Das extra breite und besonders b=
+unte=20
+Kopfband
mit dem Motiv der beliebten Robbe ABC erfreut
nicht=
+=20
+nur die Kinder =E2=80=93 es sorgt auch f=C3=BCr einen
sicheren Sit=
+z der=20
+Schwimmbrille und verheddert
sich nicht mit den Haaren.
+
Weitere Eigenschaften: leicht=20=
+
+verstellbares
Kopfband, UV-Schutz 400, Anti-Beschlag-Impr=C3=A4g-<=
+BR>
+nierung. Alter: bis 6 Jahre. Erh=C3=A4ltlich ab sofort.
UVP: 10&eu=
+ro;
+
Bildmaterial und Test-Schwimmbrillen stellen wir
gerne zur=20
+Verf=C3=BCgung.
Katalog=20
+Schwimmbrillen 2017 (hier klicken)
Katalog=
+=20
+Bademode 2017 (hier klicken)
H=C3=A4ndlerverzeichnis auf www.example.de=
+SPAN>
+
Auf der
+ABC-Facebook-Pr=C3=A4senz posten wir
z=
+udem=20
+regelm=C3=A4=C3=9Fig Videos mit Tipps zum Thema
Schwimen mit Kids =
+und=20
+Jugendlichen.
Sportlich=
+e=20
+Gr=C3=BC=C3=9Fe,
Marcus Smith vom ABC-Team
=
+Marcus Smith
PR ABC Deutschland=
+=20
+& =C3=96sterreich
Phone: +49(0)12345567/12345678-39
ABC - The Fun Swim Co.
Courty House, The Square,
Lightwate=
+r,=20
+Surrey, AA00 123, United Kingdom
Company Registration=20=
+
+Number: 123456789.
Keine=20
+weiteren Pressemitteilungen zu den Themen
Schwimmen, Bademode,=20
+Schwimmbrillen & Co?
Bitte eine kurze Mail an mich senden. Dan=
+ke.=20
+:-)
<=
+/FONT>
+=
+
+=
+
+=
+
+=
+
+=
+
+ =
+P>
+
+
+
+--sp9pxLEwghDaJRixlkdZ=_QAHPr6hfigLP
+Content-Type: image/jpg;
+ name="Durchdachte Kinderschwimmbrille von ABC (Pressemitteilung).jpg"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="Durchdachte Kinderschwimmbrille von ABC (Pressemitteilung).jpg"
+
+/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdC
+IFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAA
+AADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFj
+cHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAA
+ABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAAD
+TAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJD
+AAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5
+OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEA
+AAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAA
+AAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAA
+AA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBo
+dHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt
+IHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt
+IHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcg
+Q29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENv
+bmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAA
+ABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAA
+AAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAK
+AA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUA
+mgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEy
+ATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMC
+DAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh
+Ay0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4E
+jASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3
+BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgfCDII
+RghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpUCmoKgQqY
+Cq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUAN
+Wg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBh
+EH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT
+5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReu
+F9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9oc
+AhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCY
+IMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZcl
+xyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2
+K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIx
+SjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDec
+N9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+
+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXe
+RiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN
+3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYP
+VlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1f
+D19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/
+aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfBy
+S3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyB
+fOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuH
+n4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLj
+k02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6f
+HZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1
+q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm4
+0blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZG
+xsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnU
+y9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj
+4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozz
+GfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QMmRXhpZgAA
+TU0AKgAAAAgACgEPAAIAAAASAAAAhgEQAAIAAAAKAAAAmAESAAMAAAABAAEAAAEaAAUAAAABAAAA
+ogEbAAUAAAABAAAAqgEoAAMAAAABAAIAAAExAAIAAAAeAAAAsgEyAAIAAAAUAAAA0AE8AAIAAAAQ
+AAAA5IdpAAQAAAABAAAA9AAAAABOSUtPTiBDT1JQT1JBVElPTgBOSUtPTiBEOTAAAAAASAAAAAEA
+AABIAAAAAUFkb2JlIFBob3Rvc2hvcCBDUzQgTWFjaW50b3NoADIwMTI6MDU6MTcgMjE6MjU6MTUA
+TWFjIE9TIFggMTAuNi44AAAigpoABQAAAAEAAAKSgp0ABQAAAAEAAAKaiCIAAwAAAAEAAwAAiCcA
+AwAAAAEAyAAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAKikAQAAgAAABQAAAK2kQEABwAAAAQAAAAB
+kQIABQAAAAEAAALKkgQACgAAAAEAAALSkgUABQAAAAEAAALakgcAAwAAAAEAAgAAkggAAwAAAAEA
+AAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAALikoYABwAAACwAAALqkpAAAgAAAAMwMAAAkpEAAgAA
+AAMwMAAAkpIAAgAAAAMwMAAAoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIABAAAAAEAAAKAoAMA
+BAAAAAEAAAGpohcAAwAAAAEAAgAApAEAAwAAAAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAA
+pAQABQAAAAEAAAMWpAUAAwAAAAEANAAApAYAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEA
+AAAApAoAAwAAAAEAAAAApAwAAwAAAAEAAAAAAAAAAAAAAAEAAA+gAAAACQAAAAUyMDEyOjA1OjE3
+IDE4OjEwOjMzADIwMTI6MDU6MTcgMTg6MTA6MzMAAAAABAAAAAEAAAAAAAAAAQAAAAgAAAAFAAAA
+IwAAAAFBU0NJSQAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAAAEAAAAB
+/+EA5Gh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APHg6eG1wbWV0YSB4bWxuczp4PSJhZG9i
+ZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAiPgogICA8cmRmOlJERiB4bWxuczpy
+ZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8
+cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+
+CgD/2wBDAAICAgICAQICAgICAgIDAwYEAwMDAwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0O
+Dg4OCQsQEQ8OEQ0ODg7/2wBDAQICAgMDAwYEBAYOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4O
+Dg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAGpAoADASIAAhEBAxEB/8QAHwAAAQUBAQEB
+AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh
+ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ
+WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
+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
+
+--sp9pxLEwghDaJRixlkdZ=_QAHPr6hfigLP
+Content-Type: image/pjpeg; name="Bildmaterial (Zoggs Little Twist).jpg"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="Bildmaterial (Zoggs Little Twist).jpg"
+
+/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdC
+IFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAA
+AADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFj
+cHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAA
+ABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAAD
+TAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJD
+AAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5
+OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEA
+AAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAA
+AAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAA
+AA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBo
+dHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt
+IHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt
+IHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcg
+Q29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENv
+bmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAA
+ABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAA
+AAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAK
+AA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUA
+mgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEy
+ATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMC
+DAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh
+Ay0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4E
+jASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3
+BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgfCDII
+RghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpUCmoKgQqY
+Cq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUAN
+Wg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBh
+EH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT
+5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReu
+F9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9oc
+AhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCY
+IMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZcl
+xyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2
+K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIx
+SjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDec
+N9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+
+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXe
+RiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN
+3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYP
+VlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1f
+D19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/
+aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfBy
+S3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyB
+fOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuH
+n4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLj
+k02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6f
+HZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1
+q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm4
+0blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZG
+xsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnU
+y9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj
+4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozz
+GfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QMmRXhpZgAA
+TU0AKgAAAAgACgEPAAIAAAASAAAAhgEQAAIAAAAKAAAAmAESAAMAAAABAAEAAAEaAAUAAAABAAAA
+ogEbAAUAAAABAAAAqgEoAAMAAAABAAIAAAExAAIAAAAeAAAAsgEyAAIAAAAUAAAA0AE8AAIAAAAQ
+AAAA5IdpAAQAAAABAAAA9AAAAABOSUtPTiBDT1JQT1JBVElPTgBOSUtPTiBEOTAAAAAASAAAAAEA
+AABIAAAAAUFkb2JlIFBob3Rvc2hvcCBDUzQgTWFjaW50b3NoADIwMTI6MDU6MTcgMjE6MjU6MTUA
+TWFjIE9TIFggMTAuNi44AAAigpoABQAAAAEAAAKSgp0ABQAAAAEAAAKaiCIAAwAAAAEAAwAAiCcA
+AwAAAAEAyAAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAKikAQAAgAAABQAAAK2kQEABwAAAAQAAAAB
+kQIABQAAAAEAAALKkgQACgAAAAEAAALSkgUABQAAAAEAAALakgcAAwAAAAEAAgAAkggAAwAAAAEA
+AAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAALikoYABwAAACwAAALqkpAAAgAAAAMwMAAAkpEAAgAA
+AAMwMAAAkpIAAgAAAAMwMAAAoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIABAAAAAEAAAKAoAMA
+BAAAAAEAAAGpohcAAwAAAAEAAgAApAEAAwAAAAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAA
+pAQABQAAAAEAAAMWpAUAAwAAAAEANAAApAYAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEA
+AAAApAoAAwAAAAEAAAAApAwAAwAAAAEAAAAAAAAAAAAAAAEAAA+gAAAACQAAAAUyMDEyOjA1OjE3
+IDE4OjEwOjMzADIwMTI6MDU6MTcgMTg6MTA6MzMAAAAABAAAAAEAAAAAAAAAAQAAAAgAAAAFAAAA
+IwAAAAFBU0NJSQAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAAAEAAAAB
+/+EA5Gh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APHg6eG1wbWV0YSB4bWxuczp4PSJhZG9i
+ZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAiPgogICA8cmRmOlJERiB4bWxuczpy
+ZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8
+cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+
+CgD/2wBDAAICAgICAQICAgICAgIDAwYEAwMDAwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0O
+Dg4OCQsQEQ8OEQ0ODg7/2wBDAQICAgMDAwYEBAYOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4O
+Dg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAGpAoADASIAAhEBAxEB/8QAHwAAAQUBAQEB
+AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh
+ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ
+WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
+x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAEC
+AwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB
+CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0
+dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX
+2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8ro/E7CCWIlphjDbj1FeifDz4mTeG
+r5XmhZ08zKkHOBnoa+bdOudW1RVNpanfn5iOQK9n8H+FtX1S5ihSyDgSDzQeq80Afpz8PPi9FrWk
+28sTbGbop4Jr6e8PeI2v0jOTk+hr4r+HPwtvIoIZog2AVO30GK+1fBfhNrGCM7WKn1HSgD1S0Bkg
+BI5q+IuOlWLa1KRKMYxVwQUAUBGeOKeIz6GtAQce9Si3OelAGaIz6VIIye1aS2/PSpRbUAZYiY9q
+eITjpWutt+FTLa9+/wBKAMlYKlEHtWutqPSpRbD0oAxxD7VMsB9K11th6Cplt/agDKW3OOlSrDjt
+WqLf2p4t/agDMEPtThCfStUQcdBUgg9qAMoQ89KeIDitXyKcIfagDNEHNSCDnpWkISO1O8o56UAZ
+ogHpTxB04q/5ftS+WfSgDCvhstmC+leT6zHPOZAu76Cvari0aRTjuKxBoSNLl1BoA8n0TQHa43SR
+ZzySRXrGl6XHDCMqAR0rYt9MhhQbYxx7VoCIKOAfyoAwr/T0kt8Y7eleM+LtKRbWUquTg19BPHuQ
+gjNcB4lsEkhbcMgD0oA+MdZ051idVibIOc461ztmotbks+FDenavZfFKrbTlRESM9QK4QadBfXkQ
+VCPmwVxjJoA2dInkmVCilo1+6PWvStHWONk+0gZPJzVLR/C0yWcZjTr7VsX+jX1vb7o1YMB6UAaG
+sz6ebQKuwvjGBXB2fhq2vdc86NAXZsk1TNnrNxqvlsJMZwTXtXhDw8U8t5VO7jk0Adb4Y0CKzsYy
+YxkCu5EQA4H6VJbwCOBQAOBU/lmgCoUpNlXvL+tHle1AGeY6Qxn0NaPk+xpPJ9qAMzZx0qCVf3Te
+oFa7xfIfWsi+YRRMCcCgDg9buXjibY2PevN5PEu26mts5KjnFdL4q1BEtZvmwO3NeA32oiO7eUSE
+Z4znrQBd8S6+htXRmwTx1r5V8TatEPEl3byMAXGa9S8R6soSQsGaIck18beOvFkH/CcDEpVgNuM9
+aAOb8cWsFzHcRvmVWP3B6etfLOuaPHYPKskarExPBHavozVfEtoy7Q6+aV5715b4ils5rOV5UErs
+MADpz3oA+eNEDL4pubUDjcdhHpXZ3PhVZ495kzI681k3Oyz8QKyhRExxnHIrsrTUIGgVXuEDA4GT
+QB8867pcmma3LEynaDwcVh17V4ztILi4LwgSEn7w5ryG8tnt5huUqD6igCsg3TovqwFfvf8Asy+I
+dN0f4KaDarLGZltk3YPC8V+BvQ5719c/CX48y+GNBisbyYgxAKuWxmgD90PGfxBsrD4c3NzJcRqg
+Qkkt7V+FHx3+LH/CWftEQNpsizWVjKdzA5DNnmvqm51Lx58afh/FpGjy3WmWF0f3k4B3bPaufH7E
+1zBZobIzyT9XnmyzMfWgDgfA3iLT9U0uGX96MYV+Mc16bF4Li8QeNo7hLqVESLG0r688Gu78Afsv
+azoc+L4lkVgYwBxn1NfV3h/4LvbHbJlzwS23k/8A1qAPB/h74Jjh8UwwqreSZP3nGc1+gXw/8F28
+NtEEUARnK59Kw/Cnw5t9OvUP2ZQSOW219E+G9DNoqkrhQOPegDVh0CA6UY9g6V4L8QPDkEUksyj5
+gcjHUV9K3l2tnaEnjFeJeKrm3vbiQFlYntmgDH+G+oSG1VJCyyDggmvoeBt9kjH0rxPwhpkP2kNG
+ACR2r2cSR2+nxqxAwKAJ2AxmqM1ot0+zIyeKzLzWIkBG8A+neqtjrcf2sFmxg8ZNAGXq/gixe5Nx
+cG256EnpWCmg6Dp5MjXMO8dQgzmt7xjrk1zp4it/KLn0OK8bmtNcuZCWuI4V74yTQB20+paHb3JK
+oXbt0FZ9z4ys7aHZFBCq/wC0a4/+xnZ8XF/Kx/2Tikn0KxWDeInmI7uSaALF944K7jEYVz2jSuPv
+fF+oTsSi3De/Iqe9VoISsFtCq+uOa8S8WeIde029Ahs2aI5JZRnFAHqiarrF25AiIB7s/Sklivzz
+LcRRj65rybwj4t1XVI3V18sqeQRXe3l6raWWmfc/saANIvboSJtSfI6haa+qaJboWkeWYj1evML2
+823m5C3HJ561Va6jntzsYFiOhNAH5PeCdJFikM80qm0eTZKdvAPY/lX2L4EsrWDUtLKACGQ7ZGQ5
+Ga+NdEknNxPYztKkEhw20ZII6GvpfwamqQ/2bDpk03lABnLjIyO+aAP08+HkEUEcSttdQoBJ719C
+2M1lDCqqVBPpXw94O8bXNnpMaXiBHjGGIbg+4r6C8K+KrbVHhIbr3zQB77EVkAI6VaVKztPw1ujK
+QwIrXGAaAEWPpxUoTihfXmpBz9aAALUoXmkAqUdaAHqoz61Mq1GufrU60APCDPapQgpig5qYDJoA
+VUGKlCDNCjipQKABU5qVYuKci1NigBixD0zUoi9qepFTqRQBCIeOn6U8QdzU+eKkB9qAK3kcjg0v
+kD0q4OadjigCh5Oemc0vkc96v7ePel2cUAZ/kexpPs/t+laO0c0bR6UAZ/k+314pPIOOOa0tgzml
+2j0FAGZ5B9KwtX00zQNhc8V2O0elNeNHQggUAfLPivw/I7uEg3OenFYHh7wk51JPNiJOe4r6fv8A
+R4ZZnZowxxxkVBY6PDFKrCMAj2oAzNG8PRRWaAxg8dxWvP4fhni2tEDn2rqIY0RcADFTfLQB56vg
+20Eu7yVB+ldDZ6NHbKNqgYroeKMr7UAVBbgU7yRU+4e1IWGaAIvJFHlj0p++k3c9aAGbBSFBmnbh
+SFueKAK8ijFcrra4s37HFdTM4VSe+K4vXb2L7O4LY460AfNfj25mgSQxudozmvALi7luL5S7kKvb
+1r3fxxPC/nJw6nrg15bY6fZTXDM7AkDgGgDyzxb5yeH5+CqgHtgmvzx+MF1NaXkV7ErJ5cn7zHfN
+fqv4l0uC60R1WNSQvXHUV+Z3x402S0i1H92BGp4UUAfLlx41YyMVVpJB05rJ1LxjeS2oCqqZPzDP
+Wubwsl9uKiNiSMVXutOd0YpnOO9AFbUfEnnRFY1O/PU+tYR1a8lb/XMp3Z4NULqNo7tlYc9xUKgh
+s0AezaXcrc6UgmIkfHHvWP4jsUm0/fsClW+UgViaNdyxKoGWH8q0tX1Rm07y9pOTmgDgHg2SEe9e
+gfDbwpL4k+JmlwG3aa3a4GV7HnvXG28UuoatHAnDyHAr7q/Z/wDhuy6hazsJfOikDFzx3oA/Vf4E
+fDm2svCWnx/Zo0xGvCqMdK+z7T4f2H2FGaJM46YryP4Q2clpodojqMBQBx1r6nthutF+nSgDzj/h
+A7LzgRCgA/2a04/CNpFgiNcgeldyVxVeSVU6nntQBh22hW0JX92Pl74rWCJBF8oxgVKkobuKZOVE
+JyelAHm3i2+mjs5MA4wea+QvEHi7ULfx1FbDcbdm+Z/SvqzxjdxCwmXI6GvlbUtMW78R73AG5+OO
+aAPorwPqMP8AZ0UgOXZRiui8Sa99jtcqwzjjnpXG+C7DydLTPyhQOtcT8TvEQspBEjZZjtUZ70Ad
+DbaldalqGI5GfJ55rvbPS5xCpYkZHU8V5p4Hu7eDS7eSUqZn55/nXtdpOJ7YEEUAYN1YJHGWdiT7
+Vx1/eW8DlRyfc16BqrKlq+TggV87+JNUlt9cCq+UJ5GaAOmm1Ly8v8i+hxWFLrzvE67h7DPWsRLx
+r2IKFJX61RvLOVFVYyxYnpQBrR6rHPOYSo5OMGman4bGoQbigIxXMvpl1EyXTtIu09Aa7zStQkNq
+u47gBwGoA8cuNDbRryVolCnOTgdaxZ727lhYMuxAcnJr1fxU8IheZdu5h0FeOztPPcNypTsKAMe8
+n2xySYbdjA4rmrTUNt5IZM8jAGe9drJbKbGRZGG/Hy5rjp9PVbc5Q7yeT3oA+WdF8JaXKqJe2gtp
+Dyp2YYV9B+C9LtoNOFtDFB5cfO915NeL3PiGCTRYLldkVzCvfnp2rtfCXjq21izMUUaQ3MQw2xsZ
+I/xoA6Hxz4lTwmgkSFp7bOWEf8P/ANavVvg78W/C+rwRx2dwomUgNG7fMpr5C+JN/eX5lh3Sju4Z
+vlIrx/wlc3XhfVrnUtPkZnVwWVW6CgD99tF8ZwNaxDeBkcZr0Cx1OO4KtvHPvX5B+E/2gbuHQ7Rb
+7d5gcAsW6192+B/H8Wo6Db3iXCvlA3BoA+q0mXcBtODWgkeQMDivPtE19dTiQoeMc16XaYe1UnGa
+AIxEfSpViPpVsKKk2+1AFURdKmWPpU4WnhaAIQntUirUmOKcBQA0LzUgXmgDFSAfSgBVB4x1qYDr
+6GmLjvT8igBaeGPrTMjNOBBHIoAkDn61IH+tQDrThQBaWTinh+Kqc560ZPrQBeD+9O3j1qlk+ppw
+Y9zQBc8wZo381XB4zThQBNvFL5lQ0maAJvMpPMNRUlAEjMGHNNG0HOKTvRxk0AP34o3mm/1o7dcU
+AO3c0m45oA44prMF64oAduOetJk0wOCalxxQA3J60E07FLigCEk4yaMmpNvtS7TQBlXpYW5xXiPi
++8lit5mDEcV75PDvgYdcivJvFPh97yGQKCB60AfIWuag1xNKrO27uawNBnVtTl83cyg4Ga7rxT4X
+ns7mcxqzE9gK84tUks7yTzQEIPQ0Adlq08LaSxUbmC9K/Of4/Wt1PNeskDPG8bZx0FfoFBcxT6fJ
+8wJzwPWvDvHHhOPUp7hpIg6lDhSuQKAPxPvTPHfyo8bx4Y8Y6GrSSXz2XVenGepr6K+Inw8+w+ML
+h1jCxF84Arx3VNNa2kKKp4GcCgDyy4tpGv38zOc1attKknfIGFHetG9tJjIr4OCa6PSYz9lWNlwR
+QBXsdGdF3gHHemarYBLYrwWPNd5bIkcRLfdxXOajtkdvTOBQA34a+FptV8fWkpX90swBHtmv27+C
+Hwt02Pw1bSxqDK4DE9a/LD4OrbWniu18xVCMw5PrX7U/Ba8tU0OzCOuNo4zQB9VeDvD5sLCJNoCq
+K9ZtY9tuAa53Q7mD+zkO5Tx0rpBPHt4IxQAsgCoScdK4bV9TW2ucbgK6y6u0W3Y5GBXhnjLWESZy
+HAx3oA9BtNZjJBLjNUdc8Rx21o218ccmvGtL12SQnaxbnqWrN8Vay8emvJ5hZgvABoAh8ReKg7St
+I42jOBmvNtC1A6141coMxxnH415/qesXuq6l9ktwzzSPtVQepr2L4ceDNR0yFZ75FLyPlijAge1A
+Hs8EwsPDyqBtO3JNfMHj7UFvPGsSyNvjjbJ5r6M8RTC30eQg4AWvizxZrkR8RzjflyxGSaAOt0fx
+qYPF62yy7YkAC819L+GvGEUlmitKGJHrX5z3N3KmrG5t5CHB4OetdBpHxI1XTNTjSQkr0OTQB+gm
+t+I4pImAkAOOK+WfHPiUx60QjfMDzg1jD4lPcoolfAbuDXDaxcrqOuNcCXcC3AzQB7R4Z8QGTT03
+nble/U10trqEj6qkj4KHpXkeiSPBbByflxwK6F9ZlhZfkZUxxQB7RO0V3YKgUDPUisS4gNivyyZz
+0wa4nT/GUaWO1jl/c9KnTWmv5A29duelAGP4hubhrnDlgmO/euPaOZnEsZzjsDXW6xtluAd28AY6
+1iRwqsJUHGfegDFHnSzkPnnqaJbYGEsw4PfrWkYlRNg6k5JPeqVxMsMBJ7djQB8A2uo5jaOaQCMj
+5izVveH44ptTZNPLOA/zSR9R718W6b431NNPitJ7jeI/lUk/Pj0z3xX1B8JI9T1DVnaC5dbdFCXI
+DAHaehxQB7Zq1lY3+kSRTu0chj+ZyOp9K8uh0e6j1xo9Dh8x3GyUSAFSPcV7Jqmh6QfD1zaQ3Vy9
+1IMLKG7+tVvh9o9zFH5U80NzKJcGUjB4PAP4UAV9O+F2sXenoTDbzA8sFG0L9K9a8Hw+JvC99bWp
+En2bcEwTxivctAsYIrBY5I1yoyCvOQa6mTRbNUWdViYY6dTQB3fgDWLkRRRyhuehr3aHWpoyibyp
+9Ca8R0Y21tZxbHTcV+Ujity4urohZ0mJoA9807UpJmAPIrpUYFQa8R0DV5TaqHYiQV6TZXxlhHzn
+cBzQB1OQDyaeKxo5XY4ySa1oNzRDcOaAJaeKcE5pwU0AIOaWnBafs68UAMA9adUgSnCPnmgCMCnY
+qQJTgoFADFHNP2jPvTqXFACYOaMcd6dtJ7Yp20+tADKBT9vFO2cUARjjvT8mnbKdtoAYOvvTvxNO
+Ce1OCcUAR0vepNtLtGaAIgOadUu36Gl20ARY9qMVKFGadsoAhIwCfSucv9RSByS2K6O4G2AjOK8m
+8X3aW0LENhsc0AdNb63C84XzMk+9dTBcI8Q5zXzDpniBV1Ys75UHua9Q0vxTBKVTzVHqM0Aerq6s
+cDrUlc7Z6nFcbdrgn610YZfIDE8UAJSgE1Te7RX6gVZguY3OCRQBYWLcORVefTEnjIKjmrrTxxpn
+Iqk+qRI2CwFAHn2u+Cba5t5W8kbyPSvlzxz8P54pZZLeNgw7AV9y/wBoQXERG5T+NcP4ksIbiwlK
+pHkg9aAPzjit7+y1DyTFIFBwc1dvrbzLFy68lTj8q9m17R4015soOCTwK5DU9Mj+zMVUDigD4A+K
+Ph5ZXlKwguc4r5P1zwmps5XaTEvOMCv0G+J1tFA7FgMYPavj7xMLY2U+11Vxn2oA+dZNAVJgGG8j
+k5qnc20MUEssYCNGO3etzUdYihmMZIJHGR3rjLrU1ljlVc/Nwc0AIb6U25y3eqgMl1eBBk4OTUSv
+uiPoK2vDtlJPquAOC3egD234f25h8mVlG0Y4Ar76+E/jeSwvIYVnbyVxuUt0r4t8NWiWdpHuccc4
+Heu5tPESWWoAwymNweCDigD9h/DfxLgbTox54zgd69Ih+INs1mrGZcn3r8ddL+Kuo2MW83OFHXLV
+tWH7RBn1U2i3w+Q4LZ4JoA/WO58eQPZSnzlOPevEPEniuG+llAlDDPSvjmP403Elz5Cz+a79lau2
+0vXxe24lkZ8nk5NAHtWn+ITBEUEn0Oazde8RGfTZFLk/LXlVxq5hkZlclT6Vh32vzS2xiHHqSetA
+Ho/w/tl1f4lRsSQsB34A5Jz0r7miitbTwvGIYWWSQDlu2K+L/gWqyeJrm4XBm3ABj6elfal9ITZR
+glflToBwKAPHPH+p/ZvD1wS+PlNfAut6t53iaZ2Py7jivrX4wat5GiXCBwDjFfCN1dl9Vd2Y8scU
+AdNPcptyrA8ZrktTv1VmlB5XkEVmXeqFXdRJgegNcnqF+8v7pX4PWgDuLDxMZUEbeYrZ6jmvStCu
+WmKOynHGMivG/DFgrL5ko3YPfvXuOirEIUjKgemKAPU9OdBYKQuGArL1i6ljjY7sFvugVLbhPsgE
+LkOByc1zmsPcbwpO5f7xoAdbyyOx3Md1bCX89vsVSck9Qa5G385QWJ+nND6li7VNwGD83NAHpkcr
+SQjzG3E1RvJhEwO4rzVDRtRS4YhmQbeoJqxq7QG3dllQkdvWgA+3JJkl9wA7VhamXa33CQlfSqVp
+cbWJBGWPHNXLrJtizgFu4FAH5GfDnwBbap5eo6wsjWu4GMI2CTX1x4fstJ8H6zDf2MpisJsCZWb5
+k9q8P+EPiLw+fDJ0fXC9vcJ88TkcP9P8K941C1tLvQohYDfCvJJGSfzoA62TxN4ZfVnsINTtprm4
+BaEFuvtW54fuFtWLROGDOcqrAnNfMXjTT4raygltfKt7yP5sk7WB9RjmuS8GePdZ0/xVeW97OGmU
+B433HDc8igD9IrfxTe2WnrNHMEEY5y2anl+K8SaZvRw46SKH4z7V8cal8SL7U9IaKxR4ZVjO4Ke9
+eZWev65JHqMVxNNIQu5SM8c80AfpDonxmgnuUgLmEqdq7mBya9h0rxfcz31vE8jGCQA5+tflt4Iu
+Z4rEX88zyMJdyhm6j0r7h8IeKbO70G1luJPk2AhCcMD6ZoA+tdI1aYaivmShY8jb2r3nw6VuCrhw
+yEciviC38ZwGyYu6oiDAye1fQ/w08VpqFjbmCXzlPfNAH0zDYlWDclT0rUjhCgZ4qna3Y/s1XkwP
+lqFtWg8zHmAegzQBtbB9aXCj0qpHexNal9wrDm16BZ9okXNAHVKvGRTwh4rO067W5hDK2RWyF/Kg
+CHb+FNOApJNQXV2kJbc2AOtcJrHjC1s1IEin8aAO8M6BsZqdWQrnNeG2/wAQLS4vmRJ1JB5Ga6WL
+xlaiL5pQOO5oA9MM0Q6kfnTftEeM5GK8C1j4l2lpIy/aFBz61RHxRs3sPMW5Qj2NAH0as6t0IxVp
+MOuRivF9A8cW2oRrtlVs+9ekW2rQmBR5q8igDo8DpxTtvFYH9rQ+eF8wZPatlLqM2gckZxQA93VB
+zjNMWZSeTiuI1/xJBp5zJIF/GuNf4hWiqQkyE/WgD23zFI4I/OplAfpXk+m+NLW7jXbKpY+9eh6Z
+ei4hDAgg9KANCd1iXJNZ321d33hmqGv3Zt7CSTdtIFeGXXj1bfWPJaZQc45NAH0nDMrR7sj86z7v
+UYoScuFArym08dW40/JlU/L615d45+KMOnWM0v2gAAZ60AfRUnia1ikCmZc/WtS11uGdQVkU/Q1+
+Tms/tOW9vrskZnI8s8gt2r2f4efH7TvEOkLLBeqW6EFulAH33e6pB5DEyKCB3NfOnxA8R28Yl3zI
+o+tc5d/EVZtPZhcKDj+9XyL8UvHs1zfNbRXhyTzg0Ael3/ja0gmK212u4HnDVlr8Y7HSrtBNfKuT
+z81fGmravMjGdbmVJAOoPBrwDxv4w1VN7x3Dcd84oA/eT4d/EK31e2hnFyrIwB4avef+EotDZ4Eo
+wB61/P8AfAj9oyfSxHp2q34G1toLN2r7sg+Pmlvook/tCNsrkYegD7I8QfES1066O6dVXPc1BpPx
+QtZ5AfPQj/er8xfHPxmXU71ooLvIz/C1cxp3xY1Cz2BbtyPrQB+wl18Q7YWhZZl6Z615lrfxWS23
+Hzhj618D2fxevrxVia4Y5HrU154tkvIC0kxPHrQB97eHvivFdED7QM/Wuxu/HtvJZ/O4bI5Oa/MK
+w8ZzabfeYk7Bc9Ca9S034jvd2RDODx60AfR+reILS8v3aPk7utYdwxmtGI9K8y0TWxe3Jd3XAPAB
+zXpULB7MHPGKAPk74tws1rc9eM4r86vGFxef2jJArPlmPTvX6g/FKxE1hPxkEHNfD+o+Djf6zJKs
+WcNxxQB8uJ4aupY2ll3FvesXUdIazXlcGvsP/hBZotP3eWTxnpXz74+txZajJCybWAoA8allWMED
+t2rv/CivKyyIOa84ZRJe4JGCelem+Fyba1O3rnIoA9fj1Ga10Z9wwQmQR1FcRF4kebxDLEG3Hng1
+X1bW5YbA7mAOO1eXWOp58TyTrJ8wkoA9re9v5LUlQ+w9eelcZcXUlh4kWQGRCy7uPWt+x8Q5iVWi
+AJHOO9ZF1by6nrI2oSzNtUDtQB7h8J4rzXfEP2yUu0aHaua+0LaEWmkRRgYZhkmvGfg/4U/s7w/A
+xTGV5OK9vnPDZGAOn0oAxL662KRuJ4rCadpRgZOatXgM1yUqTTrIzavDABlnYAUAfUPwL0iSKxS5
+ZSGlbdzX1Jqc6w6e7ZwFGOteb/DXSVsPDcJ2gFIx/Kug8V6gLXRJSSB8tAHx18ade36gbZWySSTz
+XyxfScORgcV6p8R9VGoeMLhwcqrFRXjt8+VYknHagDn52Z5icHrVY2ZMnmY68j3q+QHkCtwSa3rS
+0jeJVYj2oA0tEXy/LbIA7ivQra/EZXbgdq4qygaC5COrPGehFdallhQVDMx+6DQB6Dp+oxRWu6SV
+QxGSpPauY1/xTZwpKQ64A4Oaox+FvEd9EXt43TIwu/NUH+DHijVj5t3cxpFn7ozQBwd94+RHbFxt
+UdOa4i7+IzpOxiLyfNnNe5j4BpLFta5zLnpsrWg/Zthlg2uJC+PvA8H8KAPnu2+MM9ovEEzOfSrB
++NLPZsksU5c98V9Cx/sxac6EyxTFh0AdgKwtQ/ZmsI45SqSAKM/K7f40AeD23xdUauhdnW3X1Pev
+WNK+Juk6haoq3iO57FhXOWn7N89xrkxl85rPOEjckH8xivEfir8Lde+Hd6L3Thc/ZM5IBJK+9AHz
+foVjdaZdRyXMJlgI5jVjuUe1e7+EvH4RV0sxi4bdsjdmxvHYfUVyVxo0zXjgLEEb7pVsjB6EH0r1
+/wCHPwztoLyPUNQsZJFWRZEJzk+tAHpVr8NbDxiEkuoH+0yKOc/4V534p+GVp4b1GZhavsxhZNvz
+KRX3v4O8LWFzo8FzpnBQ7iA3f0rmPib8N7jUrB7i3ikXJyx9KAPzb0HRNZ1DxjmNnMcchCtjG4Zr
+0K48MS2txJcWUsltNGuWD4wfXI716/Z/Da40i9Rw0qkuOSehz1zWtrHhySWGRg0c9z0Qr3OOc+1A
+HgXhy3lMs0l3NDHajIkjYbc4PVfpXt3hLXhb6hBahopbZ22g+v0rHv8AwRf3XhJLu1hxNHwyxrwK
+0/hlYQt4vjt7y3HmxZIVhwpzigD2+/tl1XRY4dOMzsfvHpivpP4H6Pf6VokMM0u5UbK89q4/TtPs
+47M7UiBMfGBivSPA2qLZ2jYKjb1FAH0jqniD7F4aJ83GE9cV84TfGO1Hj1NM+1ru3YPzd/Ssf4l+
+P/s3hO5CTbZNpAO6vzhHiK8ufjib0XkvD5xu9KAP2Pj+ICDRiPO7eteH6p8YIovibDpYuctK+AN1
+fNEHxIvJtLEQeQz7NuQeD7143qEutS/Fe31SOWVnjkD59s5oA/bHwFriXWmxFnzkDqa9PutThjsy
++8AAetfC/wANfHSDRLMyy7WMYyCfau68Q/EtLWxbbMGyOBmgDqvHnxEi0rz288BQCetfEPi746k6
+xcRQyMyknbz3ql8QPGM+uXFwsbuEPGK8IbQluZWldSW3cE0Aej+EvirdQ+NpXurlzBM3GW4WvVdU
++LIgsHC3BBA4w1fLl9oqx2RKDyyO445ry/XdS1K1Gw3DuAMZzzQB6t4t+LOsTazNJb3Ujx5+YBq5
+PTPjff20ctnc3bhS2V+bpXjk+oMQwdiS33ia8U8Sao9rq0jrIQN3HNAH6yfBX40xX1zIk98HKNgA
+tX1kfinDHaB/tK4HP3q/nx8C/Em48OeI3f7S8aP1OeK+hIPjxe3sLW0d00kmOADQB+u2j/Gm01Lx
+4NPW7G4c43V71/wn8H9mIBMM49a/CLw1461ew8aW+tPcuRu+cZ7V9X2nxthfTl3XQ+5nO6gD6d+M
+vxNNj4cmkgn/AHmPlwa+O5fjxNZWDSXF5gjqC3IrhviD8QpNfspFjlZ0x618jeMNVkjU/MST6mgD
+9KfhL+0HHr/jD7CbkjEmPmbrX6eeB/EUVzocTNLklR3r+Wfwh46vvC3xIstTgkbYJV3rnHGa/aT4
+XfHiwvPBlhKt0oZohnLe1AH374x1mP8AsWUK/wDCec1+cvxV8dPoniEvDMd2/sa9T8WfGOzbw7MV
+u1Z9pwA3tX54fEbxXd65rk05kYruOPSgD6CtPjtP/ZpQu5YDrmvJfG/xP1LW7WaJLh9h4ODXgces
+yxMqs+FJxVuS6W4jGPujk0Achrd1I1zKZHJLHkk10vw88UXujXDJBM6Lvz97iuK1va0rHJUZqro8
+4guSEYn19KAPs9PiVqEmlhfNbp13V5xrGtXF5fvPJMT9TXGaZeM0A3HAFV9S1FYzhj15zQBevdWd
+YHDyZyOtfO3j3U2KzKkisD6V3et6qVtZAr8k8YNeI+IXa5VzuyfSgDzSHULyDVC8Mzxtuzw1ej6N
+4z1sypF/aF0QBjG815nJbzLfNvQgZ613WiWMaRq7gjNAHqdt4mvVUNNI5J7k10dn4uJCKz9/XpXm
+V3sis8BuMdK5JNZMeprEHOQaAPtDw/r7SRoQ3T3r0I64fsigu2SK+UfCetSExjzCx7+le/6aHvbS
+PdkZ70AdfZTyXt5gsSM+vWvRtNtXSAKrHFcloemrEi8d69NsIgttyRQB6L4OtjFZBiSWLV7dBOE0
+oEnJC15H4VjL2cSqP4uK9ZSzf+z2PP3aAPE/G05uoLlM8HI5ry/Q9EiuJmUIvXrivT/FttIsc3Gd
+zGsTw/CICu4YOeaAKeq+HUg0GWQIuVXsK/PP4wWHl63duRg5NfpZ4k1AJokidPlOa/PX4q2t1quv
+y29nA00zEgADNAHyDBE8mpHsN1eg2lwbWyXDYYD869A8P/A7xVfqsr25iB56V6lp/wCzpqdzEFun
+l98UAfIviDXmZWAXkcda4G31N4LvzR97OT71+g7fsqQT5aVZHJ/vZqSH9k/S0zvt8n3FAHxXpXiv
+dcjemCK+jfhbYDxL4jil8v8AdIwPTvW94q/Z60/QtNe4t4kUqOcCvW/gb4TtdNsY1VRv3cn3oA+k
+vDukJYaDGgUDK8cVJdwjc/GK39yrCEXG1RgVjXZyrc80Acq0KiZz1JrtfAGgvqXjyFyhMUXPTvWB
+b2jTXioFzuOK+vvhl4CitbCG5CO0rgMXPQ0Aeu6Jp62XhaJcYYrn8K8W+K2sCz0G5AbBCHGDXvF7
+L9msGQcBVxXxx8X9SaZ5IFY/MaAPlu6hN1eTTShmJYnn61h3+jLNF+6BVuvTiu+s44vPxIOCa6CL
+RY7yQGJGfH91c5oA8Mi8OSbS7rvPatO10edZEJU5HQCvoaDwLf3luvk2Egz0LLitCL4VayzKyxrE
+SPQmgDxqzsTJIiMCpA54r3/4Y/DefXLwX16mbdD8gI61p6Z8Jr0MrXBZjnkhcV9Q+B9CTTNKgtvL
+Ecca89qAOal8HaVpOmB54oxx3Fc3PqOg2waMCJVHqK9J8U6VfaxfslruW3Xgcda89k+GFxdTZmdh
+9OKAODm8U6VHqLrFaBhn7wWt+z8WWIiIWLJI/uV1tt8J7VI8OT75PWte3+HGmQDacD1560AebXPj
+RI/MWG1d+OML1riLrxvL/aLg2UkXdmYYBr6Qj+G1hd3aW9haNe3j/ciQjJ/M4Fchq3h/Q9I1250b
+XtKWx1BY+IbjA4PRvQj3FAHzve+PNMhvHuJ5I1jT+FTnJryrxvd2Xjvy7dYnmVzjaF4Na/i7QrFv
+ife2WhQxzxq37x4+Y0Y9RmvUvhz4PsLK48/URGZepkfoPpQB+RngPSdXu/GukQzEtbNIAwPOfUV+
+p/hfQNPTw/ArRxwoYQMMgz0r4W074Z+KPBeoG5OWlRxJFI5yCR/Kvtzwprw1v4d2hliFvqXlgTRg
+8g96APZPhf4XB1S6jtpMwNKT0719Fah8P1vvDMkMkKksMj5a4j4O6N5cUTxS+ZuwWz619eRWSyac
+qMoDY60AfBmvfCS3MRiMG49TnpXEN8JbGNeYV2g5wBX6D33hy1mm/eqDxxXn/iPw1bWOnySooGVP
+OKAPz98ReFEsLOeBA9sP9g4B/CvENAWLRfH8rzRl0MmVdRyM9Qa+ifjD4h/seCXaqOwJBJPSvmHT
+tXS+1uSRwSknUjt70Ae83Gvo1j/osjKVGQTXEv471LTo7h/tRjOcjtmnojf2YRGyr8nUnrXi3jy4
+urPT23AMx6UAVPG3xMn1UTwzXTeYQRgHgmvCrTW2j8RW9ypJmD/MCetcF4j1G/l1XGGiXp1rL0eW
+9PiCIyyF0EgyDzQB9veFrz7eiukTAvjPpXseneHY5VE0qBSepIrxv4fMq2Fs5A24HAr3VdSK2o2M
+AMdKANeO5OkhRDIVC9OazNV8UGdWDyfN7txXJ6tqTtlgxx35ry3XNXnR2MZJ7HmgD0G51a1WQh5V
+OTknNVxrFr5iLuXk8c1876h4nkS5KO545zmqWn+LZJtVRDI2F6nPQUAfSmpX9vLYMseDkV8+eM0m
+E+UJ2mu0stXSe0UiYNkHvXDeKr1SXO7OAaAPJtVvzaRuznJC+teGeI78XV5lmIXrXWeKtcxcyIzf
+KuePWvINS1HzbkbfTmgCCe7drrKHaBx9a9Y8GK7Xlu5HLDrXiTSfOCCc5r2jwPckRxs2AoIxQB9D
+vKkGgjA5x2rEj1G6Eq7JWCemadcXW6xRd2QR+dJp0PnR7SvOaAOikvmi0YtK5PFeL+J7prtpDnbx
+xXrl3bD7KEfLKBXk3ia2Tc+wY9gaAPJZUeO7H7ws2e3avon4eeNL6ytbazWaXC4GFbmvn+6XynyP
+v5r0bwCpfU1kcfxUAfbmm6nd6pp6+YzkEdWNc54j0/yLB3xnAz0rovCJjk0qJduOOtaXiCzL2D7h
+kEenSgD5YubwnV2Q5ABrorWYLYBsnBHGaqavozRa3JKR8pPTFRo4FuV7DoKAOb1+6XzTjpXN6bey
+tqwVSdp9a1daXLMfyrJ0qHbc7idrE0Aeu6delbZFORmoNXaRoC54wOMVn6ZOryqGPyrXRTxR3Nvx
+ytAHh+tNdtKWViAD0rmZ4v3RL5Jx+tes65ZQxxPhOfWvFNa1H7FcOCML6GgDnr/ZGSz9c8Gr+nam
+DCibxkcda47UdSNy2FJxWVHPIj5V2H0NAHpeo6iRbEh8n61w4keS+L7u/rVR7qV1AZyR9amhJedF
+Xkk4oA9v+H0zS38UTAsc8Cvtjwtp3m6dFkduDXy58JvDzPLHNKu4kg9K+5fDmlbbKJVAHFAGla6e
+sUK+uK24WKR461ObNkQDPHpStEI0ycc9KAPYvAUJkSHIr3xLANphwOorxf4eQlrWIkdBX0BCp/s7
+t92gDwnxXpKFGG3nOa81S1aCckDAFe3eJkDytXmz26neCOaAPLvFUjjSZME9K8b8I6La6j45eW6V
+XJk4LCvaPGCbNPkAHY14v4Mvf+K3mQN92THB96APszR/CukxaNFsgjLbR0FTz6Xb2x+WFQPYVnaH
+rBWONHPGBXZnybyHIIJIoA4qfylQgKo/CsC+kWO2eQ7QBzXZXuky5JjUke1eOfEDV10Tw/cGRthV
+T1OKAPnL4x+NEtbCe2jky5yODVH4Ga5Pd2Chz/F1r568Xatc+I/FtzKxdodxxXsnwSD28rQxgnDd
+BQB9pYb7LuLVmMjSycmrUK3U1qihQOO5rZsNAklgLzSvz2WgDQ8C6WmoePbWBo/NUHJBHGe2a+/9
+Csf7O8LRLtVG27RhccYr4z+HdvBYePRA2TvIJY819sQOp0mAISyhcZ9aAOP8Rlxp8gjRncjgAV8x
+a58PtZ8T+I2eQtb24PYZY19mJZJdyEMAR71P9g0vT03OIy9AHyZoXwIsIpVae3e5fP3peR+Vew6X
+8LNPsYBiGKMDsFArtdQ8UWFllYimR0AridQ8eXb7ltoio7E0AdTF4V0u0TL+WMU6SLQrcfMYRj1N
+eRXfiHV7ljvuWUHsDXOz3NzI53zSyHvkmgD32wvtCuNYS1SWIEgnjFch4y8eaX4TvRHJcIisCVHc
+4r1b9mjwno+rDxFrurWMF/dW0kcFstwm5YwQSzAHjJ4Gawv2lvg9ol7J/blhClrL5YyiDCr9B2FA
+HkWgfF+x1e+MdtmQdztxVi7+It5JO/kRIi5wMmvJ9G0O10q03IY0YLjaoxzSuxUdc0Ad9N441eQn
+EyoPasuXxPqshO69cfSuQMre9RGZh6/hQB6n4O8ZanofxEsdT3SX8aErLCz43qRg4PY14j+0/wCN
+rvxN8YfD89lavounJELaM+dukcbix3EYGSWPHYV0EGpSW1wkqAllORmsjxJ5HiOSE3dnbZRt2Sue
+fxoAzdB0myg02KQKpYqCQOufeuhlvVtosLFgD3ArGt1a2hEaEEAetRXU+Iy0iq4HbNAHol/8J4dZ
+sXjkQkLxjbVGz+DNvp0sLwwGAqcDA7V9nabo1koXLoQRyRUuuW9jb2GQkbFR1AoA4z4d+G00WNCT
+tBwcZr2efU4bWBdzgV4p/wAJFFYQu6yDCcgZrzTxR8VohA6pPtdeCCaAPqcanbzS5Mi4+tcB481e
+CDw3cOkobCnIr5q0D4t/ajLHJcYkQ9C1ct46+I8lxo9xDFKxYqQOaAPkv4yavf6x4+mELFrRXKuB
+yOtcBpllJa6jBtUtC/X2r0W+s3vPMuJxuaRskVgXe20tMouHXtQB0kEpEIGC69AK4bxlpv8AaNqx
+mGMdDitfSdTd58P0I446GtPWImu9IcAZOOSaAPjrxZo9s9ysUCDfnBxXN6RovlanG2DndyK9G121
+ZPEcqEc7+gHStTw1ocl3qKyvGQmeSF6UAeteBLKdtNiXy2AAGOK9eNswtkCqdxGOlZ3hLShBAgC7
+QAMkjrXfXVvFDZMVZWb2oA8yvbMFW3j9a8z8SwCK3kIXORkGvYtQj5ZifevIfFEmI3wQwOQKAPnr
+VoS2pO5+4Qc+1ctbs0Orl1bCA9+9dxqkbG+yBkZ54rlbyALERHjJ5GKANeDXhpysRMxU84PauE8V
+ePC1vLg/rWNrTzqpZnI44Ga8j1uadt+4nB6c0AZWt6y9/flwcLmucZix5pZM+Yc0ygA717B4OnQW
+KKQMYrx/vXa+GtRW1cROcAtwc0AfQljKZZVVmLIvGTXd6YqwyDccgjjIrzfQZUnkjGQQeSa9ViiQ
+WsZz2BoAo6rdiSTyo8GU8ACvMfE0Elvbs+Axxzk16rFpxl1U3PVFOKyPEfh95rBnIyDzQB8kajPe
+f2wASQhPHpXtnw2t3l1CGNtxyc5xXnniG1WHxFDbhATvzgDoK+kPh3o8fkQSLD82B2oA+lPCtmLe
+1Tg/dHWux1GCObT2BwTisvR4NunR5GGAq/fThLQ8jgc0AeC+L7ZIHkYDBxXlBuF3FNw4r1zxlNFL
+5nzc968EvrgQ3zlWGM560AWL6MTKz7+cdK503PkEqwwQeDWibktBkH5vrWfMFkQsccDrQB02k3h+
+zZc4A6e9d1pl4jAJIRt9DXj1ldeW+C3yqea6JdaSMBg4GKAOn8QpEY2IIK/w185eMIxKXAUEj0r1
+XUNbW6i3GQj2zXl/iPE0DvG2W549aAPJ3QiQg9aVUIGSDUz7vPO5TnPNWMfueRQBQY+2Ku6ZKE1q
+33/c3jNVJcbuKm08Z1m24z84oA/Q34TWCXGnWzqoxgV9kaLpyw6arkZOK+P/AIN3Cx6VbKDu4Ga+
+z9LmD6QuemKAK84IPAxVJtuBu5bNXrs4DEYrOsx5+tRRE5y1AH0R4Bi2abDkc4r2reF088jG2vKf
+Clv5NnFx2r0K8uDFpR7cUAed+IpR57455ri5MCJm9q3dVmNxdkZOAax50As8e1AHinj258vSbh89
+FOK+YvAurqfiRcKzdZSa+jPibuTw7cRgHcymview1B9B8ZS3UpKKz5yTQB+iOnanF5URDgfKK7C3
+16O3QMZVA+tfDUXxbtbexQi5XcB61SvPjWHtXWO5APYhqAP0VsvGujrZyiW4gEgH8TCvhv8AaK+I
+em3WtRaPYXMck8p/eiNs4FfOfiD4rancmRY76SMHIyr4ryvS79dU+I8F1e3L3LCQMdzZyc0AetLo
+UqaF9r8hkUrncRXR/DPxNDo/iaSO4+4X64r1SXTtOl+FyyzMWeWL92o9a8J0TTGHjGe3dduHIyPr
+QB9yW3xD0gachiVpXA7CrMPxNupY3SztkTaP4jmvAbK3e30/vwMVvaWspBK7snrx1oA+qfgdLrfi
+Txzd6pfSnyFk2xqFwBiv0M0+JBYRrI2yNVAye9fGnwBWysNAt4pSqyu25sj1r7AVWu2EkUgWADpm
+gB2o61DZoYrZSzew5rh7yXU79iWLRoe2a7yKwtWmO9gX7kircmm2KJkkk+wxQB45Jo0jNmRyM9eK
+cmi2uPnEjn6V3upXWhaeCbqeOI9gzcmuUuPGPh6EEQxPO3YqvFAFYaNZY+WBT/vGmSadYW67plgj
+X3NYGoeNZpAwtLBUXsWNcNqetapfHEk0EKZ5ANAH27+z3qulG/8AEWmW15AJmEciwZwWxuBYevUV
+z37RvjrSYSmg2F1Be6iseJ44n3eWfRsdD7V8Uw6jPZ3glj1OK2mHAeOfYw/EGs251O1aRnfV7EMT
+8xadckn8etAF83lwV2sQB6KBVZ7hi3I5+tYsutaNG+2XxFpUbFtuDdxg59OvWqh8Q+GROI38S6b5
+m8Jt+0LncRkL9SOfpQBvNOdp+X9agec+ifnXPP4t8GR3ggfxDbvMZBGEUsTuPQcCs9vHXgV7lYE1
+hzKz7FH2eXls4I+768fWgDqTK2eqVBJMVGTJGv4V5ve+PPD8m0abe3ku59ik2UuMhtpGSvYkA+nF
+cwfGmkTz232ltaaOaVo0xaMFZlIDDnH3cjPpkUAeq3uqSQD5CHPYgVoeHtPl1W7M2p3PkWnZema8
+0g8e6A+hRy2tlq8kC3gtd/2PkyYBxy3PBB47Gmw/FbSFa2D2murDcS+VC6QRlWb5MDh88hwc+x78
+UAfcVp8T9PjBjS+iZgeges7WfiRJPiO2lEhfjGa/L+LVL+08QrKdRuopN3I8w4YV7v4W8RyKiNLc
+NKpwQWOSDQB9C6lrGo3LMQ7xgjpmvIfESzGZ/Mkc7j1XtWrceKfMtmKyKHI9etcFqniKZoJPM2EZ
+O0k80Acbe3V5bX26Cdoyo42nn8as295e3UCyXcskmPXpXO3WrQm5cvhtx5NJDqimIpHkds56UAau
+rawlrZKCVzXOyXS3UQlH7z1GKw/EQu7uBvLbcFGSBxXPaN4hFvdLZ3QKyFtoLd//AK9AHbWkhXWU
+QqVRjkcV2lw6SWTKCQNvNcpp0kVxd+bwADxWnqGpwWunyguuccHNAHiut6csvi+UggYfOSa9H8Kw
+WtrDswCTzmvItZ11Itbe4J3gkjANaumeLhbQo7KxAGQR1xQB9O2Or29pAFO3JGM0641hWGN/Wvnm
+PxhLfXqm3YoM967e2nubmNGZiy9c0Adne3gZG54brXmPiGOOSNjyMc8V09zMywFCenrXBa1fZhKc
+N6k9qAPMtXwgfYuWPauMuVWKAPnB75rpdWucMWYg+orh9Q1OL7KwUpkA9+aAOH8RSbiz9OcD0ryj
+V338k5OK6nxHrCvK8SHPevOby+eRSDzzQBjS/wCtNR0rHLE0lABVq3ZlkBB5zUUcMkjAIjMSeMCu
+hstEvJLyFRCzAkZ4oA9R8I6jIltCHJLs+BX0TptvNdaXGR0IzXkfhTwjPPeWilGWPIzgV9eeHPCO
+zTowULfLwMUAYFloXlaCruCzN8zGuP8AE17HDpUymPGxTzXv97phh0coQBx3r5o+IbNDa3Eark4O
+BQB88JC+o+L5rgruUSEKMV9TfDi1aOKJn4XsK8R8Lab5l0ssqAAn0r6o8J6XHb28coHVRwBQB6gu
+5LJNnXFYmpSsto24gcc1tRSoI8Hk4rF1Wylnt5NoPIoA+dfGd/sklAJ68mvAdSvpDqO1STk19H+L
+PCV9MjNtbB9ua8ofwRPFcmaZGP1oA5WG4keAA8HFV7m8EMDFmz6V1V9o/wBntGKgrgV5tqzMqsM4
+weRQBQudaaBiQSQaypfEE28fOcVhX0jvJtNZm8bgG/OgD0ey1H7ZEMsSBUN2CxPpXFQag9q37s59
+q0pNd32mCP3nrQAl7aokW4ryec1iSP8AJjvV6XVRPDscVjSyAk4oArscuat2AzqkOOu4VT71YtZj
+BfRyj+E5oA+7Pg7fGJLeOQkZxX29o90H09cEYIr83Phf4ghF7bKZM9Oc196eFdWhk0+L5wTgUAej
+zxA255OMVY8L2Pn+Jd5GQpqLz0kteGBrv/BmnEnzdvLGgD2Pw/bMYV44rW1w+XZFckcVpaFZ+VaD
+IwAKztfUSsVBoA8rkVmu3OCQTinvbl48Y4xWrLABIVA4zV4Wvl6S0jelAHzN8RrVZ45Y8cAEV+f/
+AMV/L0yGRU+SQe9fo544VPstzI4AABOTX5a/GnWBd+KpLaJs7TzigDwO88Q36SMqzMVB9azv+En1
+EKQJDWfeg+a2azgjPKFRWd2OAAMkmgDVl1y/mHzTN+FdN8Prqeb4v6NA8hKTThGB969K+Hn7LXxm
++JFot9pfha40rRygc6hqubeMqTjKgjcw47CvtXwZ+wroPgPV7PW/iF46abUbO5hD21iFjjjduoyc
+lhyMHoc0AdlJ4UvLf4WeZEAxWIGJiM4NeO+CNHubv4izR3FvM2yU+Y/lkgn61+h+jWng5NE1XR7X
+TtY8WLY3MSx+RCxDRhsMTgYwQpOO2RzT4LXV7DUYfsPg7SNKhi1EPKdRnjQhAoAOByRnIPHIFAHj
+KeFobqOC1tLGV7l22f6o/eAOR068H8q6Xw74W0C0vlTUtM1vUbnDsY4QsaqEznqf9k/XFekWx12P
+X9Oml8SeGtMS2u2eRLWJ5iy/wtuwMkb5D+Q6VSuPDtpceKft1z8Qr+RPJnhENrZbPkkZmGCc9NxH
+4n1oA6bTb7StG0Wz1PSvC1+kLxSSoZtRVDtj28keh3cHpxiunX45a/bW09pb6L4ftjBaJORNfM5G
+4IVBxjH3wD6GvNJPBui32hw2Vxq+qXsaJIhkn1YQ7ldtx4VeOQv/AHyBUdt8P/BGnySTmw0y6lkg
+WF/N1O4l3qpyueOoPOfWgDqb/wDaA8WwrfeXf+D7OaG3jYBY2cb5ACBkt6nb06g9Rkjnda+PPilm
+1NYvHenAW8kUKvb2CKpZ95zggnkL69s9DVqzs/DekTPJpfhPw3HK0axtIIWYsqj5clvTFbVprdnb
+3Ds3hzQhvxv8iyRS+OmSVOaAPOr3x5dayviGWfxJr+ova7Fs7iK02sQXfkqFxgquSM+mOuKw4tQ1
+e/sNXWOHx7egXqR2yx28qsieYx3EgDICL83Y5HQ19Cj4hXkMLLZeHbKMkcvIev4BRWTcfEPxY5Pl
+y2Np/sxW6kj8TmgDx+y8JeMNUv2YeCPH13A2qABZZXzHCpVgck84AK8/e3H0zWzZ/CTx7LdWctx8
+P7qKP7cJLgXepxptRfLZcZb/AGWTnqCc8de4fxz4wkBB1iZR/swJ/hWXceI/E0xJk1a7bP8AsKP6
+UAclafB7xdHd6XLq+m+BtN8q7Mt4LnX4ixXMbDGM9CpUD0656VLY/CK6s/sT3mu/D7fHdrPcCCSa
+cuAYztG2PHGwgex9OK2JNT1olSmq6ipx8x8zHPtgUi6xr6tzrmsZ9Eu3H9aAMKf4S2UniuPUH12z
+8tb83LQ2mhXLB8mM7QWxjBQ4x0zVnTvhloem3FjPc6l4guZba488+R4e8sStlSc7n6ZUfTnHPNac
+l9qUxzNf6nKf+mt47fzNVTcypISzlvc4Y/rQBK3gHw1P4hh1BofFs7xzSSiNoLaCNjIVL7ueQdoH
+t9eajT4e6HHdWs8en38zW0jvGb7VIQMuwZido5zgA+1TJeIwyZWB9BbKaeHV3BklmZP7pjC5/KgC
+j/whuhWFvapJZaYRbszxedqpcgtjJ6jqFA+nFQQ6F4Otra2jOlaIVt3Lwbr+RtjHGSOSc/Ko+gx0
+rYNzp0Rz/ZSXR/6azP8A0NULq8hljKw6Lp1qD3XcT+poASG38MW2mCytdK8Nw2ayiQRBpmUMAAGx
+64UD8Kr+RoqRollaeHLNUbcgi02Rtp45GRweB+QrONpK53bljHsKT7HAABJNNIfyFAHyhfwpcxGZ
+Zw5DcAHFbOj3xi8mCK6BYHlA1cLcX9v9llRplhfB2sDx+NeWzeNF03xRB5dwC8b8sTgUAfc2m209
+1EhZs55AzWB4itJLdTLgnHBGay/APiX7do0U8sm7cM5BrodXuPtrleSmeaAPK7iBpovtHzK3Pyk1
+QsbyaHUDHcANGTw47V6BPawtDs2gxj/OK851q6iTURHBiJozyMcGgDvXgiTSvNOGVhnJNeFeJZY7
+bxD9pVgsYbop4J9a6m58XAaeY5JFaJRgkHpXz94u8YWxv3jilBC9QT1oA9107xZE2giUSbHjGG5/
+WvNvFHxHhkLwW85Ziex7186an49vEt3tdOaTLHnB6VY8J6NqGpap9qvWdi5DAHkUAe6+FbO61vUF
+kny6E9M8c17nB4GRbFHCDO3jjisr4eaHDFDbyBAuK+iGS2XR8IFDbelAHgVn4fSw1kAoPmPA9DXs
+ekaapsghA6cYrz3WNTjs9Zct8oB6mut8P6/bXVqBFKGPfnpQBPrVklvA8gxjFeC6/erGZRu6GvfN
+duFfS5T144r478eau1peygPkMetAGPqeoPNPJhuAD3ry3WppYXOHwp7g1oy6u0liHjOPU1yus3ob
+SXZioYDNAHE6izPdMwJPHXNc7OCCc1oPdl/vc89qpSrvAIoAoVoabbJc36rL9zPPvVFhhqsWs5hm
+VlOGBzQB7toHha3vBEI4QF4+6OTXuehfDkShGa2CHjHHSvHPh34xsoJ4LaZ4xO5+Xd6+lfcHhG5h
+vdKjuH2gHsOaAIvDHgSG0kj3JkL3xXt9hpSQ2QOFBA4zWdBcW9tZoFKZPJqV9YUwELIMigDJ8SRK
+LN1U847V80+JtBbUZpixbaOp9a+hLzURdFlYjPQ81y2oafDLZOqqCSOtAHzxpPh5ba62AnbngV7z
+4cjdLFVfqBgCuAvR/ZmoEsoC44Jrd8P65HLdIgcEk8c0AewW1luKMcZPWuoh0NrjbhMjuaq+H4ku
+LeKQkE165pltD9nB4oA8j1TwessQLxZA9q8u8S+GLaCzkcRBcD0r65ureNoiNo5FeK+OLDFlNtAx
+g4FAHwd40kisYJgCAe1fOOoXck1xIx6E8V778TLWYX8g3Hbk15vpHws8feJrf7ZpPhrUW0wnA1C7
+AtbT6+dKVQ/gaAPH7p9z9ec1luDur3a5+EllZXix+I/iF4S02U8mCw8y/kB9MoAn/j9cxf8Ah74f
+afJJG3i3xDfOD8pg0REB/wC+ps0AeWHpTC3qa9Di0r4e3BZZfFuv2I4Cs+hLIPxxN/Kp7nwP4Wmg
+3aH8TPD19N2t7+0nsnPtkqyf+PUAeZZpK7zUvhv4q0+0W5htrLWrRkLifSL2O7XA65EZLDHuBXEi
+CYzmMxuJAcFSuCPwoAhpwVj0BNaMemXTDPkv+VeheDfB1xq90gaFsE9xQBieEbvUbPWo2tllPoBX
+218Ndf1ebYk+QBgcmqHhb4QxJHFKIAHOM5WvdNA+H40+VTGjds8UAekaJLcXMUSs3JIr6h8H2O2y
+twB2Ga8Q8M6GVuLdWXBz0xX1D4YsgixLjoBQB39pGIdIJIwcVw+pStJePz8or0O6Ai0fHT5a87v0
+2xs3OaAMGGIzX5+XIzWhqy+VpaxgY45rR0a03yByPrUOu4EEjdlFAHyN8YdVj0zwbePuw5jP8q/I
+3xVdvqfiS6nYlsuea/RD9pfXvK0OeBHwXJUAd6u/st/sT/8ACZ2Vl8S/i8s+n+E/OD2eibCLm+Bw
+Vdk4Pln0HPrQB8RfB39lz4nfHTxNAvh/S30zw6ZMXGuXylLaMf7JP3j9OM96/VT4Wfsp/B34U6Bu
+0fRZfHPj2AMJdXv1R0hbnBAPyxDIxkc819qQ+HLbTLGHQbGzh0bRbdPKs9H05drCPGArlenY7R+d
+WtT8H2ljoHn6oYdOtsFo7GMhASe7Ad/rzQB4Rcw6heWTHUtXj02ze1WKSw0hBuRgBz5h4zxztHeu
+fkt9Ihmla30W2nmlVRLPfsbmSQqcq2G4BB9BXX6hDE8zrG+6LJ2JEOMfWssWapklNue3U0AZMt/r
+M5IN7cRIV2lIm8sYxjGFx2qpHYyM+WUyH8Sa6UWIkTITaB71atrhtPmBjKsO4K5oA54We0gSRmMH
+jLLUjafbhd3mpn0xXW3GufaYPLFjbbu7Fc1mw6fPdy5gtnlY/wBxM0Ac0bZQ+F5HbAo+zg9VYntm
+uquNE1CBMzRGE+hIzWa9m6nDMP8AvqgDJ8k4wrhfxpwhdORIufzrTW0UDJZR+FKYVHQ5NAGaxunG
+MnbUP2dsknrW2I3YcFj9Kcluyn5lJ+poAw1hmLYRCfoKUwT45h/Ot9mZV6Rr9WqpJO+MDyh74oAw
+Xtz1ZAvsKgMMfofzrVl+bkuM1TZc56UAVVWMHkbufWpd0A5NuufYVNGtsp/exM/srYzTpEtZB+4t
+XT3aXNAEaXkKfds1cj1FRz38khA+zQRD/ZUAmmGIgn5UH4E0xo8Dp/47QACeIdYuahe5iH3bZGJ7
+uxNOELsOAaDbuoyVX8aAKklxI4PyKo/2RiqRRixOMVoMrE4I/WgJjr/KgD8ufEN46WB2u+XXkk14
+LqE06635k7SMm7j2r6S1vR4xGoZu2cV5TN4Wa71ppWZmw3ygjigD6I+EupXT+HreISEw4GCev519
+CeduWIbgQOor568AxDTLG3hYgMFxjtXsa36kjZySOeelAFjW9Si0+yfrnHWvl7xV46gg1OSF2KTn
+IR+3417T4r1FodGlZ8YAOCe1fBXjvUZZ/Ec7JuHzGgDvP+Eh1O/hnWFiCWJJ9a8e8Ttdxal5Uxk3
+ytyc9a9o+Humyap8PbO8YbnZnUt34JFL4z8JQhrK6lX5vNHagDzvwv4Se8SGYxFmJHUV9H+G/DEd
+msUjrtI7f0qp4QsbaG2hJQbQO4rsdR1NbeM7AF9RQB2ena5baZcJbqVj59e9d6mu5sN7OMkce9fJ
+epeI1F7kNu+bA5r0jTfEqPokMssilSvAz0oAo/ELW7iOWSRXwnORnFZvw68U3M1wYkY5z83PauK+
+I/iC3urMJASzE8kHtWH4A1BbG8JeTBYgg5oA+0NQvU/4R5nZsDb3NfDfxT1YS6lKkRxycYr6A1rx
+dbr4dkRpwo25BLda+KvG+ui/12RYjldx5FAFW08QLFYeRLywPJNYWqao1yCiMcGsI7h1PNQliW60
+AWY2JcDBNX5I/wDRsiqdsN0oArcaHdbYIJwM/WgDmpBh6irTntyvLDFZzDDUAaGkz/Z/EFrKSQFk
+BzX3H8P/AB2sVjbx5cpt4J6V8R6DaPd+JIEVd205PFfWWgaNcQaMpjiI+XjigD3e68fqQcTge26s
+6L4iq8/k+ZlyOxr5Z8RapqNh4leMxzcccDitXwi2p6j4ghzBK3mOBuK0AfVVn4ge6vV3Hare9Wb/
+AMRi1/dtKMfWuRg0fVVdCsEnH6VzHi6w1m3sw3kSEt+dAHLePfGkouVEUnAbnB61U8I+L1MyNvw4
+PPNcBqvhrxLq8uYoCB9M1qaD8OvFEEqO6MPoKAPu3wJ4nS50+BPMGfrX0NpWqW4t1JkBOOxr4N8K
+6Zr2mLHguG7jFfRPh2TU50USMQwGaAPfrjVIDAxDgccVm6f8NPGvxKE0mgaTcy6ZG224v3ULBDnu
+zsQo692ArqPA3wv1DU4LPWPECS/YZmRrSz5H2hSfvPj5lU/wgct2wOa/RDwL8OtV1Hw1Z2PiGQaZ
+ocfzWelWqiKJcDGSo43H6lvVs0AfBHhv9kPwrb3EVxqF8mqa1vDGSwsVvXTn+GWZTGh90hYj/np3
+r3Gy/ZK8CajPBPqPw9s/EUgBIvfE2pXF+4IPACu/ljr/AAouMdK+7tL0vRtIgs47OygiZPM3kJjd
+jv7/AFrXsdTtbqxikMUUcRjBjRjn60AfKml/s6eF9Ks7ZdP8I+CNGEI/dLp+hWyEEnOWITLdD1pu
+v/s5+CtfsooNf8D+AdcXcFRdR8OWrhs9siMH9a+x0dXICxp0HGKz9QRwYmjjDBXJ49lYf4UAfl38
+Q/8Agm/+z3470S5gg8Cab4H1UkgX3hl5Ldom/wCuZYofoVr8v/jP/wAErvi/4L/tHU/hpq+nfEHR
+LdWlFpMhtdQCjnABykh47MD7c1/SNqGrWs3h+bIa3e6vRHuRsEsG25J7cKaozaiR4v1SJCk1lDbo
+6RMnKk9efTFAH8TGtaL4q8G+KrnRdf03WfDmsWzbZrS8heCWM+6nFR2/iTU4ZAZnivgG3f6Sgc/9
+9feH51/XD8bv2Ufgl+0t4bX/AITLw/HFr7QAWmp2REN7bZBYbXA+Yd9rZHXgV/Of+1v+xZ8RP2Wv
+GovNQjk134dX90YtI1+MDk9RFMo+5Jj8Djj0oA8i8N+IfDeq3aWOoQxaXdsBhy4aJyewPY/Wvq3w
+L4RWyeN0twyNyrKMgj1r84AcMDX1f8AvjqPCHimy0HxfM1x4ancIs8nz/ZST1z1A/SgD9LvCvhyO
+WzQmHHHcV6Nb+HPL5CA/hW34cSzn0S0vLQxTWs8ayRSIwIZSMggjjpXd21ur4+UUAcjo+kPHqiZT
+AHtXteg2pV046Vhadp6mbcFFehaRbbQSRwKAJdSGbZIx1NcJqsYChO5NehXC77gscYUVxd/D52sK
+o55oAk0yMQ6S0h7jArjPFV4sGi3DE4+U967m7AgsEiHGBkisbSvh3q/xH8RjTbYPBpq83lyRgIv1
+9/zPb1oA+Yfhr8ELP4qfHNfGXjG2nv8AwppVz/oWmW675b6deQ23uikc9jX6kad4USy0C2a68i3v
+Eh8tZUXAt07JGvTOOC35etOsLHwV8IfAcNjZJBbusYTftBmnx2A64z2/M968X8SfEPWdfnlS3kXS
+9OzjJOWb/E+woA6vxN4n0TwnZPaaHDFNqjg/vT8zD/aJr5+1DU73VtSM2oXct3KTk7jkD8Kluf3s
+jnzZJWY5aR+rVVWOOM4Rd7H1oARlj2DbGfrWbOjBiRsX2HJNaUqSFSWZR7Cs4ozPy2RQBVImKfM+
+B6ZqPygw55zW/DaWxiLOxZ+wAqrJEnmbVAoAyvs6g5UmrUU9xAMRTSJn+6xBqdowO1IqAdBQBG7T
+uNzMzMe5JJqsY2A5BNaXltsyaiwCTn+dAGd5ZJ54FKEVSCTu9quMi9RTGBAx0oAgM38Kqqj2FR7k
+br1pWT5qURrnmgBrJFjoDWfKqljhMCtMquDzVOYjoD3oAzWUDsKjxg8qD+NWGwT71GVGPegBhcAc
+RpmoWlbOAo/KrWxcZJAqBgM5AoAarOw5EY98UxuGJyCfpQ289qjKOex/KgBJJ3xguR9KrF8jjLH1
+q0baQqGIx+NV2iK57mgCAD5snmlZgeNuKUgjt+tOCSEfLGT+tAH5wX+2a/KbuO2agNjEkLEBRnkk
+VnR3AvpUZFfk8gDireqQ3i6SWhilXA6UAZ9z4lh0h9oK5XvmtTRPHSSXbNJPlSMjc1fOfipdZkuX
+MUU7H0wa4rTbnxVa3237LdFc4BZTQB9i+K/ESXehuA2QR0HevkHxk0sepF/4G6ete3eHbPX9d8My
+O9pJGIjtYN1Ncr4t+H+v3mms6WrAqflyKAOu+CV+r/DcwthtlxICD25z/Wtn4najBF4ahcsFCTA1
+mfCPwNr9h4RuftKGL/SWIA78CtD4keAtc1TwvtQtF84OMdeaAMLQvFsMGjKGdSxHr2pNT8TCS0d2
+bgjAINc5pHwv1eKGPzJ5WGOg7V3Nt8K7u7wHaVlA5HrQB4deeIiuoSRgk5OQwruNJ12aXRUTcdwX
+kele8eF/2UvFvinUFOk+Fdc1JW6SpbMI/wDvs4H619GeHP8Agn/44kdJdWn8PeHIcfN9rvt7Af7q
+A/zoA/N/VWnuZwwJcnt6U6zmubDc3lMwA5Civ140z9hn4X6c4bxN8R7q7m/jh0uxVR9NzE/yrvtO
+/Zk/Zn0ZQJfD/ifxNJjlry+ZFb8EC0AfhdrXiDVdQQ28Ec20ttBOeawbTwjqV4zO8Lsx5zjNf0P2
+Hw7/AGftE2/2X8EfC7On3ZLyHzm/Nya7C01bwvpQC6P8NvBWnKOnl6bEMf8AjlAH81tx8PvETyn7
+Ppl7KP8AYgY/0pbb4V+NbmYBdB1QAnqbV/8ACv6Z18f3cagQaBoMI9EtkH9KU/EzVkPOlaf/AMBQ
+D+lAH86Om/BbxIoD3Wn3ye32Z/8ACt+X4R6tAis0MipjnchGP0r+gp/idqZT/kFWJ+san+lUZPiP
+PIMT+HNHnXuHtUP/ALLQB/O/qnw4nUHezAj0WuHvPBkkJIBct9K/pMk8TeEL6MjVvh94buM9d2mw
+t/SuT1HRPgLqsjLqvwl8LSbvvOliqH9DQB+C3wx8LLD4ruZL+PepiwmfXNfc+haFp7abDiNPuD+V
+fbtx8GP2X7ubzofCbaLMejWV3LGB+HIqNvgj8JlgxovivVtPwPlWaRJQPzwaAPhnVfh9pWoX8krW
+kZJ/2a6Lw94G0/Tb22dLaMbWznbX1VN8DZMM2keL9C1EZ+VJ8wsfx5FcrrXw48c6JbPKNAn1CFRn
+zLF1nH/jpzQByo0q0WDcEXOPSuG8RaLBfOiFUIB7Coda8YyaLI9vqFnfWUw4KTwMh/UVxEnxEgeX
+eqO1AHW2Hg+0Qg+WufpXXxeGbcQD5EHtivL7f4kwKozE/wBcVoR/E+JhtSJyT04oA9ITQ7eJs4Xj
+2r3T4SfD621XVotb1i3nm0eGULHaxxnddnOCB6qDge5OPWvDvhSt/wDE74zWWgRxzQaZFE15q1yo
+/wCPe1j5dv8AeOQi+rMK/WP4E/DmGOW3vJrRjpUM5W0WQ9sFi38wBxjmgD0j4e+B2treDVbmNTFK
+7OlqXJWIKAAB6nnGfwHFe96dZRwafCoBOIgu1uQKrWGmwW1pEqbokWPKKe2WzW6m0IACMZwMUAZN
+5p8bQSOAEKWzBMcDJrlb3TJLSGGGIN8qruI9T1ru70A6XPnP3D061lXNzaCVmLyFgSOB6Y/qKAOV
+sby9tbiGKQGVCCMHr90jg/UfrXTT3PnWXnWzL5+0GNX4zyp5/MfnSrBZz3AZeCGz09GBrj9RsDF8
+XdIura5leLT9HupJbcdCSFVCT9UP5UAS61okFzLZwoEtRbXaPMNvysCCB+TN/OvK7xJLbQ/GGpFv
+LuFvGto/mPO35Qo/FTXrHh3Xv+Ej+FWgatqdvHY3t/MhlgLYL7ZMZHPQ7Qa5vWNHj1TwpqFrp8cK
+M2tpKVLbVcKGJH1P65oA5R5p7TU4dLjkaG4isdxYjDKRGF6/8Co+I/gXwZ8WvAl38MfHWkxa7p+q
+WG9WuBlS+4qOnIZSOHHI4rZvp1l+JXjqQW0ZS00hI4GHq2xjn/vmtXQLq2k8Q+H7oLi5bR3d2bHL
+Fz3oA/lZ/bT/AGKvEP7K3ju21KK8l1b4f61dyJo1xImZrYj5vJnI+XcASFYY3Bc4HSviXTbN7vUE
+hVlCuQDnpX9mHxg+Ffgn9o39mTWPh54sSK9uJ7Z1hP8Ay1jdQCJEP99CQQfz4Jr+SXx/8NfEPwh/
+ai8Q/DjxBbtFqmk3vlq5HE0TYMcqnurKQcigD7R/Zd+KeseFdKHhHXr+S+0aOXbp4c5aDPWPJ7dx
+9fev0w0fVoL3TIrq2kWWCVdyOvQivyK8K6RLZC1nO2RiAJE29R/iK++fgz4pSa3Gkzzbo3bCZP3J
+D0/Bv5j3oA+wdIfdCp9a9As/lsx7ivMNMuVXZHXolrdJ9lHPQcUAOu5Nsbdq5e2G/UZJj0Xpmtm9
+lLxMfUVe8NeGpdbaWaac6doVsc39/wBx/wBM489ZD/471oAs+FfBV94x1yWWST7Dotuf9KvHHA/2
+VzwWx+A6n0PpeseONB8IeGP7C8GW8DtHkGc8pu7ux6u3vXDeIfFJudMi0HRojpfhu3GyC1hOGl/2
+nPUknk571wEiFmI259APX+tAGdql/f6nqst5fXUt1cyH5pJDk/T2Ht0rPWB5DuwzADqa02iBky23
+aKrzyNJ8inCjj0FAGe0X7zglznt0p/kbVy/HtUyYQ55J9TxSStxl+noKAKEg+U8DHsKphdz4xV+T
+cQM/KvYCogAG6UAOCRpDzyfSoFjUvlmCipiC3XgUbRnvmgBWhQr8vI+mKjFseCCnHvU5kITGaiMm
+eOcUANkwE2l1/Cs5gA+etXXWLGcsTVNuvFADk542irqSpHGQbeF/cnpWeAw5pSQV5yfqaAI52Qk4
+UA+1UCGZsKp/CrTYDcClWTb/AA5oAovBIRyh+tVmgOeSM1tGQsOMr+NVJQD/AHifagDJMBz0b8qj
+aIitHe44GfxqF1J5Yj8qAM85B9aTL7s1ZKc8gVGVB6ZPsBQBAWfuxH0qMmT+8xH1rat9IvLkBljK
+R/3n4FTzLomkwl9QvEkYD7oOBQBzyQzTNtQO5PYDNaa6HMIhJdSJbR+rnn8q5bWfitpGmQtFpscW
+4DqoryK8+IGu+JdditIZJI45HwSKAPeJ77w/p5K7jezDsOlYlz4k1CT5NO09IF7MVxWtoPhq2ttE
+juJx50xXJLcms43Vl/wkbW7yohBwFoA+UdN+HdnayFxGoHcEVd1DwvbpbbBCrKB2HSu+OvachIVd
+2K5jWfFdnAjYjXB6CgDzOfwHp9xKZHt0z6basWnw70oygvaRnJyPlqWbxqgkbZHx/Onp48RCC6qv
+tigDudK8J6ZZWbRJbxoN2SAtLqHh6xmtmiEMZz2IrO0PxJqniLVEsND0+5vrpuCsUeQPcnoB7mvp
+Twj8Dte1ER33iK4FojYPkIxCj6t1P4fnQB8/6R4bMbLaWdo88hbISGMsx/AV6Hb/AAL8R+LkWHyI
+bCAn5mk+dh/wFen4kV9gaJ4J8NeHLYLHAly4HIC7U/EDlvxJrpm1Hy4BFbokEQ6Ii7QPyoA+dPDf
+7K3g/TQk/iPULq9YAbokYIv6f417Xovg74d+E41Gg+ENKE6jieeASP8A99Nmrs16zHLN+tZk94xH
+yvg0AdJd+ItWeHy4Wht4gMBFO0AfhXJXV3eXUp8+5Rh3BbIqByZCdxY+5NR+XEOnFAFdlQAgykn0
+UcVTfIztDVoHaOBtqFlBPP6UAZ5RiM7x9KrSe4/StZkj3DI471G0UOeAMfWgDGbp944/GoGPpz9R
+WtJAOuMKR3FVPLjyd4bHtQBmNuyfm2j2qPAZeXH0q9KsXOCaouFAO04oAryRJg8of0rLnjwTgD8K
+uTSgA5b865bVNYtbK1kklkjiVRlmd8AUAST3ctsrbWXGOQQK4bW/F2n6VayTXlzbwMOgJwT+FeTe
+MPiw8sklh4eX7VKW2+cF+UfT1rz3SPAHjXx5rr+Xb32oS/ecKCwQepPQD60AdprHxviikMenLPcE
+dCCQK5N/jv44Rx/ZjS2T54ZZ2z+QNe2ad+zZYaJoI1Txv4i0Dw1aqu6Q3U4dlHqecCvN/EPxB/ZN
+8FXDW0njy68RX0Rw/wDZOniRQR6EZoAz0+MfxV1SDZqel6d4itSOYtQ07zgR9SM1kT6p4Zu7oN4m
++HM2gPJ1udGkIXPr5T8fkayL39qr4AWp26ZY+OLoDu1rGM/mwrGb9rP4TXTeVJpniKGA8fvbNGIH
+4MaAO2XRPBl6QNK1eOZD/wAsp4jDMn1U9fwJrq9J+GMcrCeFFmU/dI5FcDoXxy+BOv7rW51W1sXb
+7n2+0aEZ/wB4jANe9+EIoWaDUPAviWz1a3dwBafaFmjkJ6AEEkGgD6v+Afw8Hhz4a+VbW8EereKb
+5FnuM/OlrCxCx49C+5z67F9K/UPw1pTaFokNjGoRIWcKq9gsSgfqTXyr8KNBk1DxjaE2UcK6LZmE
+FRnc5kClugxwp6dck55r7RVTvlyMgmb+YoAUsylV6HCZ/KpBIQIQO7nP606VhuI2AkOv48UixHdH
+kdWYfjzQA93LqM881hX1tE8uf9Vlzx65reVeV5XJBx71n3EkbRhsBhyRz7D/AAoAyIZGWfK5xt7D
+jopqO4kH9qzwhczXVt5LNj5gu9v8TVoZaVgP3Yycen8NGoIkd7pF2zKuydlL+gJzn+dAHP32hW9z
+rvhtYpnSz0lHKbFyNxUDnHpzTXtEPhu8dPNjlN0mxCPvZxz+NdIiwx32qWon2yMTJ5e3ouQc5/pV
+kyWn9krc/aI2jSVUEmzjO7AGPxoA4q/0qVp/FMNuFFxqGl8MRgB/LCjn8BXJfZZtMu/CcZysg0ie
+JgOdxVSf6GvbWjQ6tPDujPmW+dm3njIzmuevtPtpZrK5HlubO1laMqOucqcUAfOJ+3aDpXhrxPpp
+d47bWJBcxD/lnG6xDB9VyPwDV+cH/BVL9mya7g039pLwZCbsaUBb+ILVFw8USsdzj1ClgSOw3HpX
+7AW9jZjU7GOOGJbC5aTzoyPlDkx4b9P1rN8c+GLfxf8ACv4keENSs0u7C5s/NSNl3CRJYSkq475A
+cf8AAqAP5fPCN59s8M2c+GBIGVJzg/XuPSvUPA/iS98OfEiBp3c2ss22Q4/hzkN9Rx+VeeWOiT+E
+fEeq+ELtGiutFv5rHazbiRG5Cc98rt575rT1DW9Osru1lluIRMFO6PPIHY/zFAH6k6Dqq3+lWl9F
+IsiyLyVOQT0Nel2N8WhXJr5X+B2uwaz8PZIYbhJhGyzRYOcIwH9Qa+tPAnhu88U+KotNtj5cQG+4
+mPSKMdW/w96AOv0Dw+2umW6vJnsdBtiPtd2B8zHtHH6uf0611GtapG+lW1rZ2i2elQjy9OsIzhfd
+29T3JNdXeWNtO1vpenp5Ggacu2NB/wAtW/icnuT61xfiO0+z232yWRUZ/ljjHZfSgDhrkLG5Jbfc
+v1x0QVXmliisvLiG64kHzOeiL6D3PrQ5y2VUs7H5R61C8Mnlsyq0mB88h6CgDNkVQepNVH4OW4z0
+A61dKMTubOO3vUTxrnoCaAKG7PzEY9KCVB3MC3oO1WHVU+Zzz2FVxHJMchdq+9AFZwztuPA7YqI/
+eq20bDjOfxpggY5JxigCvjjvSbGPsKumMKOTmgKPwoAoFeMVEQfTFaLRr2qu0Y9KAKZGfembOelX
+vLOeAKay49DQBRKHrUJq8w46VWdTnNAFQqDnPFN2DHWpiM9qaVNAELLjvVd8Z5JP41cI46CoGXr0
+oAqMBnqaI7eS4k2xRyyH2rotF0c6lO7ykrBHy59ateJ9Yh8M+HXe0twoVeWC80AZCaGI4/Nvpo7a
+MdQTzWVfeJvDmigpbqt1cDuea8sfxPqHiW6ZWungiJ6Zwa6/SfDWlQ2n2q5lWaXrljmgCC+8Q+I9
+ZsHewja3ix8vGK8G8SjxD57m7uJG9ga9z1nxAbGxlhsIRtUdQK4LQdPu/FmvSC8ZfLD8CgDyLTLJ
+rq9JmR2X1Ir0vRINK06ZZpIcuvIyK9R1Pw5pHh3SS7QoWA64rz6Of+0NWWO1ssx7upFAHVQfEKCG
+XyJYnEIGAcVlXtzouq6gLu3uBHP14PNdtJ4X0t/CbSXEUaSbO49q+eXez0zxpdRLITGG4GelAEEH
+hiaSRs7yT1rP1XwXJLEflLehxXvFt9nW6PCAH2res/D0+v6mlnptv9ouG64+6o9WPYUAfJ0Hw933
+CxiF3kJwFAySa978F/sxvqrQ6h4mH9mad94Q9JZR/Qf54r6j8M+A9D8LBbqZItR1jHMzL8kZ/wBk
+H+ddRc3zuSS1AGJ4c8IeEvBWkJaaBpNpb7P+WnljcT6/Wtqe/dyfmrLkuSemSarku/fFAFmS65OS
+T9KqPOxHHGfWjbz70hUKpJwAO5oArszE8kmoyDnOKrRarplxOyQ3kUyp96RMmMH03/dz7ZrRR4ZY
+w8TpKp6FWyDQBBg47gdqjZSTnmrTKScc0bDtI/lQBT8sZ6UxgRVo5B6fmKjY+vGaAM913MMjHvUJ
+G1vl5HrV51UHtVOQ8c/yoArPKR1ORVORlYHIOfap3IPaqTnqfSgCFtgY9ce9ZV3PHGpJcCpbu6WG
+FmY4Hc187fEL4lCxeXTtKcS3p4LjlU+vvQB1HjL4hab4ftWV5PNuT9yFCNxP9K+YdY1nxB4z1Rmu
+pXiswfkhTIUf4moLWwvdZ1Y3V68k7O2Xdzkmuj1nW/DfgHwg2r+I7yCw06E8FlJMjkEhFA5ZjjhR
++OKAOq+H3w0h1W/+0306aZolt899qEo4Uf3V/vMewH1rH+Kv7b3w8+G3giTwZ8GtIj1fVlzHcXko
+BiUjglnH3m+mfwr4E+LH7SXi7x9DJoOh3F34a8HLuUWkEmyW6B6mUr2P90cepNfN2PfigD0v4g/F
+/wCIXxP1t7vxd4jvr6EnMdkkhS2iHosY4/E5PvXmdLjp05pKACiiigAr6e/Y3stT1n/gpT8IdDsb
+y8ghm19J7iGKcokscCPOysMgFcRHIPavmGvrj9hZN3/BUn4Ytu2lGvmB9P8AQbgf1oA/qx+DNlJB
+4c1C+kBZri6RHbHTLKf0IP519E8bTlQMsRj6nFfPfwjuHX4dLFIyt/pLMdp44m4/Sveopj5x3AkF
+zx6fOf8AGgCyrB5H+UArIAcU8lQYt3H7w4z680y2A8y54H+tJ65//VVC7mEVrKWcL5dyjHHYFh/9
+egCea5it4o5Wydiu2B1rKUK9qhRS6lcgrzniszVxI8d9FHK6ss6ZBPGGA/TisrXLTxM2lWsWg6hc
+2MluSknCsJAcHPI4x/WgDr0jUyEMhxk4z/n2qvd26XKfZ5UJiM6lUxzyD0/KvNtPi8babcxyazrl
+3dRyhlVOPvkEr0HrUvhHxUdc8O6b9s1J4L9bgpI8icbwWHLZoA9HFnFJqM8xhY3DQ7Gkx90FAMH/
+AD3qtNpkcemw6esLLbpOXRP+ehVep/HmoLe/tm06ZLbV4by4a8EcjKuclSAy4/DrWYPH+nXHi6Cw
+gtZ5S0xiRxIuM55bHoKAOsiilXXrm5fBZYAh/wBnCg/zP6VXa2EPhizAzlE+ZiM5Bzx+ZrE0jxZF
+rF3/AKLa+XHdSHeZH+ZAFAPGPQV01yzzeGJhEN5VQBz1xigDj5tNtr22tIri6aC6QmZGVMBRgdfw
+FbjXFrZNp93PKf8ASHW2JYD5skAZ9uQKwvm1KfWrWOZQXj+zwn0bG0c+4BrVuLG1t7PT4L3/AEgW
+qJL5ZXnKtuB/MAUAfzh/ti+BJfhZ+3J8QjHCRpt1fG4tG38YdN6e44yv/Aa/LqXxTfX/AI71W/vp
+pFmmibagfhSOQB+VftT/AMFVoP7I/apllEsjR6p4fs7pUZAqxPEZ4zg/xEhlznpxX4eaHoGp+Jfi
+lp3h3QrOa+1K/u1t7aCFSzMzHA6fWgD9Pv2F/Ft7rniHVNMaGWSztLFo5HC8LyHQE+pJYCv2W+GN
+lqFrpuqXNsoWS8VYWlH8CDkgfpXyT8BP2cm+Afwa0jQryxxrupQrdX1yw+aeRhyPUBegFfoBotqm
+ieBbO0AVZAm6Q/7R5NADNRu4NM05UdwkKLlvVzXkWt6gdR1A3EjMUXiNWNa3iC++26o4EpkRT94d
+PwrlpVZiTjag6CgCrDcLHcF5E8zPUeo9K0bnUXntDGIoYUA6DtWS4Ab/AOvUZDtHwpAoAhkK/eZh
+z0FVncYxGp+pqZo/mOck+9N2D+7QBVK5YErub1Pal2cZY/masleOh/KoiozzmgCsyjt0oBUZyMmp
+SuTzTSo7DNAETEEdABTCcU9kb0qMg96AI2NREnd0/SpzjHTNRsD6YoAhZznmmkseen4VKUPpTNjZ
+56UARl+OmeahYbj93FWDwemabyegA96AKpjHcc1CyelXShB55qMp6igCg0R69KgI55NaDKACapyA
+HtQB0fhzVoLGaS3uR+5l6n0rptT8OWGvaeRHJHIjDgE15eQfpVq31K8syPJndB6A0AZWp/CBlneS
+1UxnPVeK5i48BeJLVCsM8xX0616nF4w1OMAM+8D1q9H41l/5b20bj6UAfPOoeFfEwt2Ty2Of9msn
+RNL8TeH9QeVIHcE5PFfUw8VaZMv72yUHvgVKuq+HZh+8tgp9xQB84anqWp6hGFu7KUgdflrPt9Qk
+sFymnvuHTC19RbfCsy8pGPwqtLp3hN/+eQ/AUAfJmt+JPEN9bNBb20saEYBwa8sbQNWmvjNNDISz
+ZZsHJr75bRfCrdGh/IVE2heFv70P5CgDwzwh4T1bxVrHlW37iyjINzduPkjHp7n0FfT+l6dpnhvQ
+xp+lRbFx+9mbl5j6sf6UsEVhpGixabpcCWtlEMKi9SfUnuT61TeVnPoKAJ5rkknByaqHe7c05V6d
+c1KF+tAEax9zT9o6VIFJPFS+Xj60AQ7FA5Fch4y0Ntf0XTLCZLu50QapBLrdlaOVmvLNWzJCpBBy
+eO/IBFdntpjnA46igDM+KnxY+GI8KzaP8Kvht8RPE2sW8YijtItEextIj0CmWYKgA74z6815x8NP
+Bmp+GrPWtX16/Fzr2u3CXN3awZFtZBUCpDEDydo6ueWPOBxXqjs8j7ndpD6scmm9P/rUANKDPIph
+XjgVJn86TvQBWZfwqFlGO1XHweQapyNyRxQBVdeSf1qjKBjirjnGeaz5WGDnt0oApy4C8cYrGu51
+iiYswAFaFxIEQkmvC/iV43TRdJe2tnD38oIjUHp7mgDlviR8Q/srSaTpkge8YYdweIx/jXiWk6PJ
+qF291csXBJLFv4j70tnpk+oTyX907EMxd3bkt6/jWn4m17RfCfwq1PxBr850/S7WE7IyfnnlP3Yw
+B95m9O34UAc746+Ivhv4beDH1O+YXcudltbwkBp3x91T/M9BX5ufED4i+IviN4xbVNcuNsCEizsY
+iRDap/dUdz6seTVfx1431bx546n1jU32RD5LO0Q/JbR9lA9e5Pc1xmD6GgBKmjgmlmCRRs7H+6Ka
+VAU7jhvQdqtQXU8cXlRlmTPKdFP19aAHxadcPeiDaGOCW2fPt+uKjkto0yPMcOOxjIrWtNWaKQRy
+Sxxq3BWJcKPfjH9aoahNB/acoijZwD9+STcT+WBQBV8mIrnzdremKWOESPsJAbsT0NRed/0zi/75
+pRMmfmhU/wC6SKAEeGSOVkZSCOa+lP2NtTj0n/gp38HLiUqI5dc+yHdjH7+KSEdfdxXzsk6Flw+M
+dFkHH510HhnV5fDHxS8NeK7IvBc6TqlvfJtPQxSrICD/AMBoA/sX+Guo+R4ev4R8ixzSOF9AXDj9
+DX0rG6eezM4ALZH44avib4U+IrbV9LmvoXBtL+JJ4VU/MEkUbSe3Tafxr6W1DxZp+kRKklwHlC7n
+ReoXbgdfXrQB6NDOU1ddp3RzRs7EdPlAx/M1xviG/kj1nxBbpHK6HSBcJ/d3JIO/rhh+VcnH8SNN
+gaC8SC+uIo0KyKsY7r259cflXOXXxHsL7xJ9qGnatbwyWL28okRBuDY+YfNxyAaAPUH1wB7m9kiW
+OOTTYbiZeuzJT+jH8q6K3vdUntIRDaRtMYFZsybVwQuDnB9+1cl4W1DRNamjmQu8gs1iljlAxIq9
+BjPGMdK7W2vYrfVRC4eILEsS7sYfHII596AHW+ju1ys99J5zrJ5qLuPynjA/DmvHItHtbTx1ruh6
+hB5c1xqzXdosDk7lfDAe2cH2zmvfZLmKO3aQsCACRz1ry3VdR8Kz/EDT9cuoJ4tUssqkwzyCCCCO
+5waAOTlivdLvbe3ZJbVYklniEsO12wpzzk9yK5/wZ4fnufFpjNsYF8lm+3PchhGxUjIQc5Oa92eP
+QfEkSGaUT/uiqljsZVJBIz+AqfS9B0PS72SfT8tJIuxh524cf1oA5/RfCkGmeJ2mNzcTyi3KtO3E
+eDxge9d15SW2iyBTvVFLgk9T1p0kkcLKduSRjC81mapemHw5euBjy4GPX2NAHF+ENWtb+S6SW0tL
+O+MzZjTJDBcAOPxLdam8TaxZafLdzSgtNJElqhdupds8D6DP414n4X8QS2mvR3iswaG0LTBug3hn
+/MFlFa0+v6tqPjyxsjDG73t6Og3BVDKgPt0J/GgD80P+CvS+G4dA8M3s6yL4v+xeTYFWG1oTzLvH
+sdmPcmsj/gm5+xPceF/AVl8f/iDpMo1vVIN/h+znj5tbY8+dz0d+o9F+tfS3x/8AgzB+0h/wVl8N
+6FrEM83gXwbpkVzrZKZinkZ9yQZ9wvze1fc/iC5GnaBbaHoitpum28KoIo3HlsgHG3HTpQB5f4gi
+h1D4gaYjSNcW9hCXMrnOcngGuQ1/XJrq9aG3kIgXg471qa1qUdtBLFHh7mYfNjsK4UhmySKAKzDg
+ZJ5qCTewGGyKvBAD0z6iqrkhj0FAFBlUHBByfWiQlVxUjfez196jOXcc/jQBVEeW+fjPoKRkOMIu
+BVvhW6kmkaQf3V/GgCiI3yRxmkMIGdxBPoKmZ2JxgCmbeOTQBVeMA1Hyp4HFWtnOajbjvmgCszZ6
+ioGxn1qd+W5qMoO1AFY8nGKQoAQTkmpmUnikAx2oAi28cYpjKCeTxVhhmoynHNAEO2OoyF61Oygd
+8VA+KAIzioXNPIqJgc9DQBXc5B7VBjByatMvB4qBhyaAIHKkVCy5qVlPWmfNj2oAqOmDxUZXnkVb
+I/SmFMnrQBW6Um4epFStGRnvURX5uRQA0y9fmYU3zTn7zU5kUj0qLaR2NADi0h5Dn86C0pH3qbtI
++tJ8x4oA9ayXbLU/bz2pyrx0qVUJ7UANVMsKnEeakVADzU4T5uOaAK4TH1pcHvVjHqKaV+WgCqwO
+7P8ASoWX1q04x/WmbeenFAFXb14FRsvHB5q2wPpUG35ulAEQXvimlSasgADNRuRjrigCm5wpzVGQ
+kkkc1cmPGaoSN15zQBTmIyeuKzZX2qSTxV6Vhz6VzWq3iwWjHcBx60Acr4t8R2+kaHc3MkgQIpPW
+vkZYtR8W+N31C4WVvNk/dLjPGeFrtvHGszeIvFY0S1Jkt42DTle57CvTfB/hmz05bGCeVYC5XzpN
+m7yl/DqfbrQBx8nhW00nwpeavq+o2ml2djavczmZwscaouTz3Y9K/Jn45fF28+J3xAaCweW38I2D
+sum23I83sZnH949vQfjX0n+2J8eU1rxBdfCTwffF9BsZdusXcTcTyg8xDHYEDd6njtXwEsTqpYna
+FPX1oAgRC2Wx8q9TSlto44z371eaeNnV3VNg+5EONx9Wqk7kyFj8znv6UAM6H58+yipFEs7CONSR
+nhV6UxUZznnk1uWIW0DvKp8xfur3zQBc0jwtcai26QyRp/sr+lbdt4W0hlcSzXEsi/eVHAPv2qjD
+4rvBK64C7m3YjXknp+FWYddgsbtpdouJWydg7E+poAi1LwtYxSq1pPcxocfLKAxA9eKzrjwlfRqz
+W8kN0AM4DbT+RqS48R3jhsxW/p82Sat23jCWOJBc2VvOAMZUlTQBxs9tNazbLiGSF/RlxmiKdoxg
+HcndT0r1nTtf8Lara/ZdVQQ5OAs65XHsw6GsrxB4BeBDfeHpDf2TDd5YYFlHse9AH77/ALDvxMsf
+GX7GXgDVRcBtS0+L/hHtZQy7jFPBgQsc9A8flkfQ81+jt/oVvqOn2WvNGJpQnlyowBxtPBx69q/m
+s/4J3fFeDwZ+1ne/DXxFcvaaH40iW3tvMbalvqUR3W7kHpu+aPP+0K/pM8HasNX8HT2dyhSdWKSw
+5wySrx+GetAFZmhOlBHjiGD88eNv0zjp9KxJoBJFJLBBbkLgOSCxX8PStCTesrwygxDgN8uSxFXt
+MubC01OJ5WTy/uSgjG5T7UAYunXtxaq8aTBJAdyMvylfUfQiusHjeG6sobHV0kKIpH2qKTbIhx94
+HtxVDxda+HraxS+03UoZCxxtQ5wPeuBtHS41GIujSRAkkbSSQPQDoP8AaoA9Z0vWYrnXobZfFQuI
+HjaT7JJEftQQYyTzgjoM4HFafjbT1061tLi0mt5ZDJmR5Eb5l2ljnHcYJ+ma+WfFN/4t0LWNN1fw
+nFawvNcNY3F2/KKjZIDRnkqRuO/OcqPWpT4k8ZeLPjDYeGrS41XMTK168NtbyWku9GAjkKyM8fBO
+AxJHdR2APqnwXp0d9o02sapqdxfWse5ooYl8mL5QT2OTgep/Cu80e+s9TspdTtPlsGJWIBSrDaSD
+n1rwXUNXk03Q7jwNEs8Rs9Qt5E1NMrCFdtrK+Ox6fjXslo5tbA2bJDDEjkxND0ZDyMj1oA3WvXDc
+OrgHhW61zviO9LeDtVi802rfZnJkyDjj3xWXqurx2+IjIApHLZ6GvP8AxZq9xJ8KNaZzuKJ8vq2e
+g/GgDzLSNT0K71TWxaarcpNclR5V1akeUoZeMqTkYAGa9v8AC+npd+MtO1CAwTxWcAcyp/FxkDn1
+fbXx/wCE7q6tdVgGqMo86Lbw+dnfb+HSvuPwfZT2/wAPraR4vJuJowQq9do4X+p/KgCDSdDi0N/E
+muy7FvtSuGmkkePlscBSfpwK8v8AEWtLFZybCqTyMSI1PSvZPFeqW1j4CmE5HmEDDK33/qPWvli5
+kku7+SeQkljxmgCptaWZpJTucnnNDgKpBAFTNhV5xiqUrfNkDIoArO2FJBHWqbFidzflVl1yckgV
+BJt28c0AVZBnmoWIVOOvtUrDPOaZt4NAFZie9N6joalZfmxT0C45oArFDj1pm1uausU28kVAzfLh
+elAFY8DmoDyfSrZUnnk1CUJagCvtHfmmuBnrUxUg0mzmgCtSYqzsHoKNnHSgCmy8VCfxq664PGah
+KjmgCmwJqJlOauMn41Cwxnj9KAK3TqKjPXpVrHHSmke1AFM8jpULLntV1hxxUR6UAUGWoCuM1eeo
+CKAKRU5pMEVbPWoWHNAFc81GU461MQaaaAK5XBphx6VYI4NQt1oAiOKaaeaYRx3oA9mWI7enFTrH
+g8j8KtKpyanCADJzQBUEZ9KeF/zirYRjyAAO1OMI6dCO9AFQr8oOM/SoyCTnH1rQEfyBffqRUBTq
+KAKDjLY/Wmke341ZZDzxUZU8GgCuemajKg46Cp2Hb3pmOBxQBWbgGqkh5Oauv0xVGQdRQBSlYniq
+Lg4J6mrkpw3GM1nySouSwNAGbdShEbPTFeEfEXxT9g0treBwbuXKxqD39a9T1+/MNpKVJztJwPTF
+fNfhvwP4++Onx21Xw/4DfTU1eysJbxp71PMjt4I2VSVQMN8jOygDOOuaAH+CdDja6+13IklJO6V8
+YLE981wv7S/xki+EXwZl0zSHMfjHWo2i0kjj7PEeJLj6jov+0c9q83svi78YvhT8RL9PiV8MH1nQ
+1uHtzNbK1nIfLOBwGZQO5wO/WvgL4wfEDxL8UPjvrPjHxJB9jkupSlpZR58mzgU4SGPP8Kj8Sck9
+aAPNw0s108zyvLNIxZyx3MxPJJPcmppZw0EaFfkU9P75/wABT0iMVizZ2ysM5/ur/ie1UGcs29sZ
+/hHpQAOxLlj94/pTAMtQBnJPSpwAq8/eNAFyBkW1K4AJPLHtTxcxCUFmJHRsDNZ2SzcmtC0sGnfd
+ISkXOD6mgDZtfsEu0wyqkhIA3Lj8K1b3SIbrSy0W2K9Q8N0D+xqutzZwWkVqQhDDb5ePU9TUsEd9
+YyMsatdWvV4gcsnuv+FAHFyKySsjghx1B7Gq+cZr0K60VNRvku+bSHZh2m4LH1xVaW18M2ciRTah
+5jH73loCB+IFAHDDvW3pWvapo8yvZXUiID80THKN9RXSxnwe6OhuXBzhSw/+tT38O6XfRs2nXcUh
+HQK3+f5UAXNNvbHxJ4lhvVuX8P8AiK3KzW11A+0iRTlWB9QQD61/RJ+yD8e5Pih8E7XVdWvYv+Ez
+0hEsvFNssmWuNoAjvlXrtbo3o2fUV/NiPDOotrYtYtqS43Lvbbn6ete//BT4peNfgV8XdM8XaDff
+aJ7Z/LvLeUbormBuJIXB6qw/LrQB/VdrFlLqGnQ6pZuLrePnWMcc9CPb/PeuZubZoCq3BUz9CinP
+P9T+leYfs8/Hzwh8W/hJaeKPCF79q0WYiLULGY/v9JnP3oJQeSmc7W6Ee+RX0Rf6MG097jS1WS2b
+94+eWj4/VfSgDzGaFWYB0Yvn5EK/KPw7n9K0rFI7Xz/ORSJlGAoBwcHqfTn+VX0hhWfzbhku5c7Y
+12nafTPtntTo454rlNkYuJ2yCuOCfTjpQB0ug29vf6rJaNaWQhntnty0wDosn31YBuhB2j866iy8
+J+G9Dmk1vTItusNbpDclSEIVAQpGfTPYc/rXLpLc6gsMcSi1lzumjORsYkcjAyfqcVuzSalBqdvb
+yy22qJHEyuyyES71wSwBHQ8A885oA4cadOnxDuBc20V/DeSF3V02pKpKnKsPuupUHa3Ddq9Du76L
+SdACRksETAV2JKj8eayrW7iaZtsb+ci/MGzvI9SD1Fc54gu3lL7IyUC4ZwvvQBkX2rPc3zqrt5Tc
+8+ta2lQLqHh0xTxrcOzLsjfkZ7MfYda5aCzke+LsrRgjcMjqMV6f4V0W/eNnRvK3IPvrxCnGSfVj
+jge9AGRp3w58Pah8ThqqWwNtZgebEExGX7YHqTXstsDJqgaOSPZjbGoO0A9/8BUCiGBBpWnId68z
+sMFlJ6k+rn07DiuV8e+I4rTwp9ihjAvsDZLE2MAcYI65oA82+JN/qDeMG0y7zHsG8r9eleb5AyO9
+XLqe5vLtrm7nluLh8bpJWLEgcDk1TYYBJ/CgCrKSfaqsiHGM1YdS2TULDnmgClJxkdaiKEg1acYa
+m7gFPFAFQxgcmm+X36VMxGc8/jUZIoAhZVB9TULL7VbGO/FMYDmgCmYs9aNgBxxUxPGKjyc8YoAb
+tphUEU4ueahJPf8ASgAKIOvNRkLkkClPXOaaSfpQA04z0qFjnOBUxGQahYUARtu7GoSM1YNQt1oA
+gbpioT1qZhzUR/WgBh6VEc+9TVGx96AISKjI4qVvQ1ETQBA696gI4qw55qBueKAISOvWomGQamNR
+mgCDbxUZHNWDg1C3WgCI1Cw5qc1E3WgCIjimECpT0qM0AfQKR4we9TBM8dKvpbHk9gOaeLbr396A
+M8JxjHWpVjO309qu/Z8deRQE+T360AZzR5bGfxqBo+K1DExJOOP5UxoeMZFAGS0eKhKDNaciDOcZ
+zVZwNv3QCO+etAGcycmoJFwOPzq64wG5wcdqrMec0AUXAwc/hVCYc9a0ZWyMHGazZiBmgDMnzk1g
+Xs4RDzx3zWzcvhGOa878S6mllpE8rnG1SaAPH/ib4pMIGnWrt9pmyPkPIHrXxv8AEHx98Rfg5f6B
+8SPhjrl9o2taW7R3rQsQtxbyH5kkA6oSF/nX0GI7nXfFk97MHIkfCA9l7V5z8aLfTdF+GeqXWqwK
++mrYSLMGHDkjhfqc0AeB+KP26fFPib4U3vhWXw1ZJFdzJLPcXcv2l+AS8a5AwjMc+vGK+XtZ8WWO
+r6TLBJo1lHIOslucrk/X+hry44LnAwM8D0q7DdvBC8cKqTIApyM5FAEbJOynYkxgLccHBx/hUcsM
+0UiiWNkLLuXI4I9R6it+Oe3t7S3vdIuZodQtzm5t5iCrH+9H6j1B5+o6en+E7vwp408NXfhTXrS1
+sNeumA0LWGuPJSznzkpIMYaKTpzjaxB6ZoA8S6JjjNBO4+tW7+wutO1m5sbyIw3MEhSRD2INRIgY
+Z7AZ+vtQBNa26u2+VtsQGeT1rWmlf7LugIwgHI7DvWGzNJxuUDHrxx2rf0xAsAaVgI15Ynpj/CgB
++k6SbmT7TdNIsfYd2rSv/EVtYlobEC4nHBbPyL/jXPalrMl0Da2m5LfoSOr/AP1qktfDN5Lpv2y5
+aO1t8jAdvmbPoKAMq81O+vpN1zcSOOyg4UfhVEAnoCa7WY+HLOMKsRmuFYAnHYe1NstcgtLyaQW0
+kiuMDEI/KgDi6fHJJFIHid43HRlODXeXGoaFqgVZnNnN6TwfL+YqG/8AC0B037Zpt1HKu3JCvuU/
+Q0AVtP8AFk6KkGqJ9tgHSTpInuDXRywC6037ZZX0l3A3Iyc7T6EV5fJG8UpSRSjDsauWOo3enzlr
+eVkVvvr2YfSgD3T4PfGPx18F/ibH448Aam1pqUDBNR0ubLWupQ/xRzR9GH6jrX9En7K37a3w0+O3
+h60sdM1GHwz43jjH27wvf3G2UN3Nq7cTIT/D97tg9a/maurZbnS7fW9Lk3kf8fCgYI9QRXLG4udO
+1u31TS7q4sp0cSQzwSFHicHOQRyCKAP7e10fR/EG6a2xb3v8aou1gfdOoPuMis1/C2p6RdmUJJNb
+sQTJDyoI6E+h69a/m5+AX/BT/wCLvw0tbHQfiZZp8VvC9uAkc1zMYdSgUcDbOPv4HZ81+vvwf/4K
+Z/syeOLe1trvx9qPgbU5QN9h4rtm2ox/hWdMgj6kUAfUepxlFdmshNK52by2D90jOfTn9at2ULaT
+4HSO5kmlaZ90h8xm7DCgk+nHFdfofxK+Fvi+xEukeMvh5ryv0NnrcDFu+ME5zXRSR+F3VZIf7BuO
+QVT+0UC5HA70AePlkubm2SxiuhI6ENhi20k/mPpnFd/oPh6+vYvIvvs5tfu5ABI45461NqPjj4R+
+ELU3GteJvBGjMvzNvvo3IJ5PAOa+dfHP7fXwH8JyPZaJqsnii/GQnkFba1B9TLIVGPpmgD6v/wCE
+P0uDybi8cMluCecIgA7sT0ArxTxh8cfDkXii18C/D68t9W8RzNi4ltBmOzToWB7segPSvy1/aF/4
+KKReJPBsek6dr1vYWssTeZaeHJ8mRt2ArzsOgH9xT7Eda+3/ANkX4Yy+HP2e7HxX4ks9Pu9V1xU1
+KSdW3Sx71BjjZiSWIUjJLE5z9KAPsuztk8PfDyBHdJ5Nm6YueWc8swPXOa8N8TX8uo6lKzFn3NwW
+bJA9M16F4j1fzrdYEZgAPm5rym+kAkZup7UAYLLgY61WZCetWnbLEk5qs5684oAqSAA8GqT9ScfS
+rr45x1qu47nrQBSKknOPwphB+lWTgn1qNgOtAFZkHvmo8Y681YNQtyfagBmAeTxTHUYzmpMd6jYD
+bjmgCuajI571Z2Z5pCAD0oApsM5FMZT25HvVnAwcimFeOKAIAnrSMq55zUhPvUZbIIIoAiIHaom4
+FPY96hY5NADCahbqalPWom5FAEDVE3WpyPWoWGDQBGe9RN3qRutQtQAxjzmomPWpD0qM0AQseaiN
+St3qI0ARE9aiY8VK/X3qFqAIy1RU9vvUzFADSfaojye9TEZqIjBPvQBGabTjyKbQB9bra9OPrQbb
+HQV1bWKhQcHpz9ag+xYA4yM0Acy1txggioWt9vb8xXTtbfvCWHJqo9uM47jvigDn2t+Bziq8keD/
+AA8HFbzxfIxzznGOlUJIsnlehoAwJYyVIAAPvVGVT1AwBW5PH8m4DnFZU6nJ4oAyJcdQwBqoT8vP
+FXpIyCcgVRkHBGeaAKMzdev4VmTk461qSjCnPXFYt02FPP60AYN9MFjYk4GK+e/iHrEE1nJpwZmu
+ZnCxhXxtGeSfX0r2XxBerb6dK5bGAa+WJHfXPH1xcZJQNtT6CgDtvDOlK2nglRuI+Qmvg79t/wAd
+JFd6D8ONPuGDj/T9VRG4GfliU++AzfiK/QC91qw8JfDfU9b1GVILOwtGmldiBhVGfzPSvwm+IPjC
+/wDH3xl8QeLNRdmn1C7aRQTkImcKo9gMCgDlIlGDuAwRyfQf400DbCZf7xIQH9TTQx2bBxuPJpHI
+Mh252DhfpQAsX+uBB2kHg+lTPKyXxkUBCWyVUYX8KhjK+YA+Qp6kdqGYFSp5weDQBvndqtpM6Zee
+AF13HLNGTyMnk7SfyNY7txtXO0dD/Wn6feS2OqQXEWCyN0PRh3B9iOK0tRskXWN1vlrOdfMgIOcA
+/wAP1ByPwoAo28KsPMlOEH606W4lvZI7S2VhGTjH976+1LczEItnAMnHzEfyqzC8dla7YRmdh88h
+7fT2oAt/Y7fS3j3P585Uk7R0OOg9veobvUJrjd9pnZYzj90h/maypblgzHcWdurHrVMsxJJJoA0B
+eRx5EUSD0JFSR6tNGVIVDj1FZNFAG+2qwXD/AOlW6MCMZApIpJbOc3Ok3UkX95N3X8O9YNPV2Rsq
+SKANue5t9ShIlQW92vYdD9P8Kw3Qo+CKsMwnUcYlHf1pQROmx+JVHB9aANDQ9VbTdS2yEtZy/LMn
+bHrWzqemRW2+OM7oJzvhYe9cWRg4Ndnos41LQJdMlb/SYRvtyepHpQBiafoepatcyRadbtczIMsi
+nn8KpXlhe6ddmC+tZ7WYfwyoVNdLp+s6j4X8VRarY7ROv3lcfKT3BqHxV4v1XxdqqXWp+QpQfIkS
+bQP8aAO0+CGrS2n7Q+gaY04jttWl/s4+YSUjab5EfHqGI5HNfWXxS8FfH74dXamW1e00m6P+j6jF
+LLLb4zhQrqfkZsZwwBFfCPhDV4NA+LHhjXblZHttO1a2u5Vj+8VjlVyB74Fft1fftFfDDxZN4S8W
+ve6xfQ2mlyS6bon2ZGguJ2+VZZWQsUkVNyhGX5dxPWgD8zNT1u+ufAZt7y41O18UnDeYLpjsKyqD
+tbrux+hBqbWtM8DX/hSS7utfN5qZK+WE1FrjzBkZ3bs4PWuo8Tab4m8TftEjxDP4fuLOwvtZDxCO
+xMcG6WVTtUf3QABjuATXc/tc/A/XPAGoq/iPRvh1BewfJHqnh2ZrU3O7BAe2dF3Ec8gkjI5xxQBy
+XwL+FXhn4pftTeFdA0fz7uzspEu9RBwVREIOCfdsCv6Y/Dc8eheBtP0a1bYkcQGwHAHHpX5Q/wDB
+O74NxeFv2eZvH+oW8S6trkpdGZcOsCHCj8eT+Nfp/oyyT3T3LnK9qAOmvrgsvJz61yVw5eU81rX0
+3VR1NYjHjrQBXYcVWfpVhzVdqAKrDrUDZ561aPWomXIoAqFee9RMMc8mrRXmo2X2oArHrzURAHv9
+alYHNMI4oAjYfLnH5VERk1YIqIjnNADCOeKibOT0qU+xqMigCEnnNMap9tMK80AVSOOahYc1ZZe9
+QsuelAEDdc1E3pU7LULCgCEjmoiKmPWmEfSgCuRxULDrVkio2UYzzQBVI61EyirRHPNRkc0AVStR
+Ec1bZRioSKAKrCoGFXCKrsOaAKjA571GwzmrLLUJHJoArkcUw5zVgrUZU0AQ00jj1qUjmm4oArsK
+jIwassOKjK0AffphPcGozENvI4rpX02RVkd1Cqo9KovbFImLDnHHFAHOyW/zDABqrcWyJ/qyHyM8
+jke1dI6FLdoWRDk53YyR9DWdLCuCcZPagDl5oTuzjjHSsyWLDnrn1FddPaOkQeXCI65TuTWJPGAo
+OPxoA527iIyAcoO1YVwpAPqK6W5T5TnkVh3Awx75oAwZlzu9az3ClsvkYHGOtac4Iboc1mTE447U
+AZVw2Aea5u+lwrc1v3pIzyOnWuL1KfaHJJoA8m+IOpmDQJlRvnYbQPrXmfhjSzFbfaHUhuvNafja
+/N74vtbFTkbtzVoGe20zwvPdXDrFDbQNJM56BVGSaAPiv9tL4jNpXgDTfAGn3G251Mia+CtyIVPC
+n6n+VfmWAa9M+L3ji4+IP7QHiDxFK7PbvcGO0Un7kS8KBXm5H7vPQt0+lAEee9AGaXGTx0p3agBu
+M0+Ndz8/dUZOKYc9KUMVHHB70AD/AOsJ9a3NPuXn0yWwHzTDL22ezY5X8R+tY0Kh3KscDHX0psbt
+HMGRipByCOx9aALEW6NzISQxzn1pksvUA5J6mr+okSwxX0YAE2VlUfwSDr+B6j61j0AFFFFABRRR
+QAUUUUAAJByOtTE70DjiQdcfzqGnKxV8igBz/ON/fvU1ldSWWqQ3MZIaNs/UdxTMBZBj/VuKidCk
+pVhgigDvdbtop9OFzDlklUSoR79a4EjDEV22hT/a/DM9m53SW7bkB/unrXJ30Pk6lInbPFAFSvob
+4Xak0ngK5gWTE1rN8oz2NfPNb2h+ItQ0CeZrNkMcoAkRhw1AH67fszfGqX4Y/GDS9V1WxTXfDU0L
+W+r2DRo7shwUkjD8b0YZHTIJ5rzz9pP4w6B+1L/wUI0geCtM8RW2iLDHp32TV4AhEiOfNkCqzAZy
+OevFeYfAK5g+IFrOYVMV9asBJDnP4/Sv0U+FXwt0vT/EB1+60fTl1MnbFcfZ1EmO53YzQB9Q/C/R
+hovw60zRbaLyLe3gSFY16AAAV9C2sIs9IVO+K4rwfpixwRkrwozXbXknG0HnpQBmTNuctn6VnuCe
+lXWGTUDJgnvQBSIqu46irzJ+dQsmW54oAp7T3FNK4q2VANRkZoAplaiZeatMMVC4wOKAKTDmodvN
+WivNM29aAKxU4zTClWivFM2/jQBUKGmFfarhSmEYPSgCtt700rxVgrRt4oApMneoWSr7Lz0qBl70
+AUGXk1XZeKvsnX+lV3XigCgy4J9ajI4q0y881EVoAr7aYR1qwVNMIzQBVYc5qFhirRXn1qJl4oAr
+MOKgI5q0y1CVoArsOKhYVZYVEV+pFAFUqahZeKuFahYcUAVSOabipmHNRGgCJhUR6VO1RY5oAiph
+qQimkZoA/VKWzyMYz61iXdirwnK7XXoa7V0ygGKzZ4PlbAFAHnNzaNCmTzzxWXJGNx6122oWyE8n
+H9a5O4TDlQQTnGaAMeYFvvdhj8KxbqIAEDBrflXLE1k3AC5AAyO/WgDmLgdd3PNYVwoBJ6CujuOS
+3T15rAu8FmHVaAOcuMgNzwTWPN16Vt3OcngVhzcDJx9aAMC++WIn2rzPxBdiG0mcngDvXoepy4ib
+n9a8J8eaiYNEnUH5nG0AH14oA8gs5k1LxpeXjOHG47PoO9eHftS/EY+E/wBnK60iznEeqa0fsyYb
+DCP+I/0r3jTtOtNM04zLGiSMvL98da/KX9pTx0fGf7RF7bwSb9O0r/RoBngkfeP50AfPyDccnknj
+n1pXI8w46KNoqRV2Qb89B+pqA9APxoAQDmpMdqRQcZpWPHoaAGY+amH1qdeELHvUfvQAmcR7R1PW
+kYcZpWVkIzj5gG69jTCcmgDQspEcvazsFhmG0seiN/C34Hr7E1RljeG4eKRdsiMVYehFNBwavXH+
+kWaXOcyphJfcfwt/T8PegChShWIJAJA61Yso4ZtYtYbmQxW7yqsjg42qTgmt/wAWaVY6L4ung0i5
+nn0qbMtp57AyiIk7d+0bc8Z44oA5jB9K63S/Afi/WrWWbS9A1C9jj++Y4844zXJlif8ACu78MfE3
+xt4P0i4sPD+uTWVnM+94jGsi7sYyNwOKAOMvLK70/UHtb23ltrlDho5BgioERnJ2o7YGTtGcD1rS
+uNWuNQ8RHUdVVdQld90of5N/OTyuMfhXQ23jO+0ldSHhy1sdGi1CzezvIkhE2+JuCN0m4g+4waAO
+KAycVJFC81ykS7QzHALMFH5mmBWJwFJ4zwKlEUklykUKiSQ/dCc5oA9L074M/FLVdPE1l4K1ya2J
+ykxtyFIPcE9Qa0JPgh8SSAbnQpYGVcfPnmu/8N/tgfHfwtbwWUXieC+tIEWMW17YxuAqjAHAB6V7
+r4b/AG+r9pIY/HXw/wBE1iPpLLZfumPvg5FAHx9b/DnxvoOrrcXGiXDwAFZPLOeDXL61oWrrdmQ6
+VfoBnJaI1+k2pftffBXWktbXSPhhrGpazdyBFtSiKoJ6cjknPoKvR+NvhVfNHD4y8Ha54IaQhVkU
+i4RifRcA0AflLJa3MIzLbzxD1dCKg781+y03we+B/iPTPtWleO/C6wvHuIvR5BQ+/ofrXn1/+x7o
+3iS3kufC1z4Z8SQhtrSaTqMchyeRjBzn2oA8j/YI025vfj1rWEdrU2qhj2Bycf1r9vNE0xBqcMMa
+4SMYNfAP7Ofwj8YfBLx3eo3hcQabcjLzX1vIj57bW6EV+mHhCzkuFjuJYwryHJA7UAenaRai20kM
+RgkU2QmSYn8q0ZyI7VI144xiqO2gCuVqBxxVphyarMOtAFYjmoWqwwqFhmgCuRnNRMMGrJWoyuaA
+KjCoyOtWivNMK+xoAplKjK1dKcdzTCh9KAKRSmFeausn4VEynHegCoRTSvNWdtJt5oAq7D6Uwrg1
+c28VEy0AVSOaiZfbmrRU+hxUe00AUWT2qBkrRZKgZeOlAGc0dRFOTWgVqFk+tAGey1CU9KvOnNQs
+tAFMjrUTL1PWrhSomU54oApMtQlavMue1QlPwoApMoqErV5lqFloApMMGoWHpVtlqErz/SgCow/O
+oCPzq4ymomXPXrQBUIppHp1qYrTStAFZhUZFWiOPeoyvtQB+trgFPcVRmHB61pMoI7ZqpMueMmgD
+mLyPIJOCeozXE3SbZ3BOST6V6Dd8oemPWuF1Er9qbaCAB3oAwJMhjg1k3J+U8rWnK23Jz3rCupQC
+d2MY4oAw7rgkDGfWuaumOCc8mte7m4OfXg1gXEimNjmgDMnf5ST2rBuXAB5AzWjcTqA3zCuWv7oA
+E5oAwdZuQsD56Yr548UyNf8Ai2GzRi2wlnX+VemeK9bS1t2Bf5iPlHcmvMLJorbRta1fVndb4gfZ
+1bt659sUAeF/HHxvD4G+BmtagsqxXTQmG1Ged5GK/Gq4nlutQmuZ3aSaVy7sepJOTX1F+1H8Tv8A
+hLvip/wjmnXHmaTpjYkKniSXv+VfK6nLY55oAttzDEh7/M1QFWOWxxmpSchn7dFqW3Aa3kDdMHH8
+6AIRwKjbkinnrUYBJoAkwTHjP0pj/LFj1NTrj8hVaRsuaAI+1JRRQAVKkjIGweCu1h6ioqdhgA2D
+j1xQAhGG9aTJPU5q/p1l/aGqR2aypFI/CF+AT6VtXnhDWbSAy+R58Y6mM5oA5ainMrI5VgVYdQab
+QBPvi+x7fLzLnJfJ/KosjIIG0+1IOtKu3PJI9xQBcgMiswVd7EEADnNXbe2aPUSDMbG8RioTGGDd
+MegqpHcCKKNIlUSAndIp5fOMdfTFbunSRzX8KSIFllUjex6k9DjvkjFAHVeEfCGi+JNbn0vWfFWn
+eH9RnIKz6kfLhfn/AJ68qp+vXpW74n+HNp8P9UAv20zxFF5oRHt7kyK6ldyuCvykEehNcI0Tw3Ql
+hmHl5wY1XKAj2/Kt7SyrLJDfwXNrFjdmIboznqSvb8KAN5LnR7k2Mml6bDoWowkNFPa/u5EPrkV6
+hpeo/EC68caZqWs6teeIrS3iIQaiDKgAGAM9c4rltB8IaXNcLfxPf3lorYlnsm88DnpjhlH0z9K9
+8g1bxToXhb7F4d8MRT2jJnz5IWnkwe5VgCo+q4oA8C+IPijV7/x60FnaPpl0kKoPskhMROCd2COT
+zWnoXjO10fwVp6TLrtlrYdjNdW2IkY9jwRk1V8V+Mb+OO6vL6AyCJ1E7WsCosZbhQSoHoe9c7Y2U
+GueO/DNglpLcXt/OreS5xsTqSetAH7KfsseLfH2v/Baztda8R6tq+mySExxXrmTavQAbskAfWv0N
+8NWKw2yHAAVa+ZPgX4OttD+HGjQQwiLZbqGQdAcc19b2SCDSs45NADpjvnPpULDFSikYZFAFNh81
+QsoxVsiomXmgCkVzURTntV0pk0nl/WgCgUOKjKHNaRTmmGP2oAzinA4ppStHy8dqTyj70AZxj9qY
+Y8Vp+X7GozF7UAZhT8aiMdaZixTTCSOlAGUY+vFN8v8A2a0Wi54FMMdAGc0fpUTIQK0zEfSoXiPv
+QBllaaUxV8xHPINMaPjjmgDNZDmomTPUVoshqEx5zQBnFKiZK0jH7VEY/agDLdKgaPnpWq0ftURi
+OehoAyWj5/xqIoeuK1zEfSoGi/CgDJZKiZPatNovUYqBo+fWgDOZfaoHT8a0mj9sVAy880AZrJUD
+JWk0dQNHQBnsnFQMlaLR+1RmM+lAGcVphQdxV8xnPvUZj60AUCnHrUZWr5jqNk/GgD6uj+PU4Aym
+fyNWF+ORm+8m0euK/MnSf2nvgnrEix2XxC0MyMOElkMZ/wDHgK7m1+MPw8u0BtvGvhyX6ahH/jQB
+98SfF+CZOZdvtismb4m2Uh3FwSK+M4vH3hidgsPiLRpCegS9Q5/Wpm8XaMYyy6vp/Hf7Sv8AjQB9
+Y3HxHsWP3lArnbv4gWThgG5Poa+WLvx14fgBMuu6ZGPe7Qf1rl7z4ueBrMH7X4v8Pwf718n+NAH1
+ZceM4JCT5px9KzJfFUDKcynnrxXx5d/tBfC21ZvO8eeHlA/u3at/KuO1T9rD4MadGxfxpbXJH8Nv
+G7n9BQB9sXXia3AOCzfjXJap4nzCwjwox1J5r4C179uH4Y2YcaZHrerMB8uyDYD+ZrwDxb+3Hrmo
+RSQ+GfDUNipGBLdzbj+QoA+9vGviAvqXmNcKiodzMXAC47818PfHT9pOO10e48L+EtQ+2ai6lLi7
+jbKx9jz3NfIni74yfEHxo8i6vr06Wzk5t7b92h9jjk15hkl8kkk9TQA+aWW4vJJ53eWWRizuxyWJ
+6k03oeO1W0jUxAlgabGgMqZHU5/CgBsmQqoPTJqQHZEAOpGTS7fMueemeaic7pmPbPFADSeKEHOc
+/hTM808E7eeaAHFvlOOtEMMczXHmXCQiOIuu4Z3kYwo9zmmHufQZqCgAooooAUdauLLusTAeVJyP
+Y1SpwJzQAqO8cyujFXRsqR1BFen6Z432WSm9ZGOMMCOa8vb72aTtQB0/iTUdN1K8Wayt3ibu5XAa
+uXqYuzj5+SeQah70AFFFFACg4OasRzsuME5HrVaigDtNLu7T7KsMkktvcfdEjDcoPuD/AI13FvJM
+bWWK5L3dvkfvLdssCM5bHXvXAWl/4eT4Z3trdW1xL4gaYG3l25VV+uf0xWTZavcWdwHRiMdh0/z9
+KAP1D/4J/wDwe8OfE39t6Gyv7xVeLQ7rUI7Vpgjb0ARVYdG5cN8w/hr9N/iZ+zbd6bKft+gNc2ar
+vjubaIeZCckfeXHAPOQR24r8FvgN8dbr4V/tG+HvGdrM8MlrI0V0y5PnQSDa6k/e6YI68gV/RT8O
+/wBsjTb7wnFPrko1PR3gDicbXSVSBggn2GMHv1oA+APiF+ylB4n8OPFHHbapJJIhMd3EYLhWXOMy
+oQzYOcb9wryb4c/soa94b/aZXxJqzXP2K2VUht7mDKqBz8ki8MOnULX7ead4k+C3xGuY7qNF0GaW
+INHdRELE7MSWyvqN3PbmqniT4cnR9AZtL1GDWtMT5icjei5+8cdqAOH8DaV9k0G2j2YIUCvVZF2I
+kY6Ac1kaDZCG2i4GAK23G6ZjQBAq80uzParIj+WpBFmgDOaM56VGY+K1fJz2NJ5HtQBleVz0FOMX
+Fagt/apPs5x0oAxTFx0pph46Vt/ZvUUptuOlAGD5JJ6GneRWyLcZ6UvkcUAYZh46VA0WOordaDnp
+UDW/HSgDG8rJ6Uhjwta32fnpSGD2oAwzHz0phiz2/StlreozAaAMdoqiaLitloD6VE0Jx0oAxGi5
+6VXaPB6VtND8tV2gOelAGMyfjUJjrYaHrxzVdoqAMox+1RFPatUxHFRmI+lAGU0fPSmNHxWm0Q96
+gMeKAM4p14qFo85rTMfNRNH7UAZDxj0qBo/atZovaqzRnPSgDKaP2qBovatYx1AY+OlAGS0dQlBW
+q8fXiq7RdaAMto6jKcmtFoyDURTPUUAZ5jGelMMdaBQUxk4oAzGTjpUDJ+VabR1A0dAH8vk+k3Wi
+/FK40K4US3lnqTWcgU8MyuYzj8a9l8YfAr4oeFdNu7vVfCutW9tCpczLEzIB1zkVl/EnRwn/AAUP
+8T6LAQRL40MSbf8AbuB/8VX7EftT+Lh4F/Yr8WahHIFvrmzFhbMevmSjZx9ASfwoA/BOGW/n1BI7
+aW6edjhBG7bj+VdI1vrVvAq/bNRU5+b96wwa/Rv9gL4KWF74f134p+J9MtbxLndYaJHdRB1Cj/XS
+gEdScID7NXqv7VfiL4MfCr4Uz2beDPDl/wCN9RRl060W2ClMjHmvtwQo/U0AfjhdXl6sjJJe3Tvn
+nMzH+tQRQXF185MjrnqSTmvt39lD9lz/AIW1qsvjnx5bXMPgWF2FtbqxjbUpe+D1EanqR1PHrX31
+qn7LvwC0jTVuLrw+1lEgAUJcvlj2VR1JPYCgD8Mv7OYrwGrOWItcmNck57V+zV/+yd8Mri0v/E+p
+aPqXh/wzaWc0ptPtZ8+fCk7nPSMew59cV88/sh/A/wCH3jXwL418beM9OW70mPVTaaZ585URRIN7
+sTn/AGlGT6UAfnuNPlZCQjce1QPbSIpLKwx7V+p3jzxD+xp4Ev3s49PtPEF9Hw1vpm+42n0LZ2/r
+Xztqvxt/Z/luJItN+C9zPHnCSSTqpI+mTzQB8frCH04ER4bdyxPaqjqochTmvr7U/EXwX8T+FmW2
++FvjDw7IE+W6toGkjU49s/yr5f1+10q31yf+yZp2tN58tJ0KyKPfIoAwRnFW4lIhdj2GBVTPIq2p
+Is1HdjmgBUbZbyPjluBVVqvTxkRxxjkgZaqB64oABy3rUmMEVGD8/enk5yaAGycIP9o/yqGpZuJt
+v90AVFQAUUUUAFFFFAB3oo5PvRQAU48rnv396bRQAUd6djK5H402gDptH8Pwatcop1nT9PiI+eW5
+OAn171X1GxttE8RzW0OoaZr0ScCaAM0bZ7jOKwaO9AEvlEknKKvYswFBRBnMqk/7IJqM9aSgDodN
+8Natq/h3UNU0u3e6gsWQXIXAZd2duB36HpXq/wAL/jh428CFNFjmOq+HxndY3LkGEZy2xuq89uld
+n8OfD7WP7Gl/4oziW98RiJF7skUfP6sa+eL13tm1C4Zdk11O+0HqFyaAP1W+GH7T3hLxRJpGhaZd
+32k6/cTbLi1vEwoUMCDHKvHPTBwePev1R8A3mqalpkaXN3cyW7BTsaQspwMCv55/2RvCJ8RftCQX
+ckZeG2YZ9PU/yFf0efDrTBaeG7Ubdp2jigD1myj8qy9OMCrKrz0NPVNtsi9M81OiZ7UANVPap1T2
+qRU4qykdAEAj6cAVIIfrWhFbs7YVSTWrFpMz46UAc4IfrTvJPpXWR6HIZACePatSLQQBymT70AcA
+Yfb9KTyfau9k0MFvuY+lVm0JuwYUAcSYTnpR5J9DXZ/2IwPOaZJozY+UEGgDjDB7Uw24z0/SusbS
+Zh/CDVdtMnA/1efpQBy5t+elNNsPSukawlHWNqjazcfwMKAOba1zURtPaujNsQOQajNufSgDnGtS
+Oxqu9oT2rqDb57VGbfnpQByTWhz0qFrNvSuwNsM9KjNsD2oA4x7NsHAJqu1m392u4NovpUDWa+lA
+HENaH05qBrU+n6V2r2fzHgVWey9qAOMa1OOhqs1sQTxXZPZ+1VWtPagDkTbnng1E1ufQ11bWntVS
+S17YoA5doOelV2gOeldM9t14qq9vz0oA5toPaoWh9q6F7frxxVR4MHpQBgPDzVdovat54vbmqrw5
+PSgDCaL2qAxc5xW48PtVdocUAZBix2qIx9c1rGKoWj9gaAMlo+OlQNHzmtVo85qFovagD8Cte0Br
+/wD4LcLpEi7vO8dW8rAdxuSQ/oDX6A/tVfDDxj8apPA3gTw2DbaUdSa61e9k+7EijavHc/MSB7V4
+NoHgHVNd/wCC9mv6vDZStpejN/aN1Pt+RC1qEQZ9SzfpX6iWMElvZXF1JJsUMQXbjgD1oA+fvGvi
+Twl+zB+yFbQ+WkNpolgtpptqCA93MBhR9WbLE+5r8sPhN4B8Yftb/tfaj4o8Y3N02gQzifWboZ2p
+Hn5LaL0JAx7DJrY/ag+Imt/tB/tr2HgDwg8uo6VY3g0/TIozlZpycSSn2HTPopr9Uvgz8KtH+Evw
+G0fwlpKqssKBtQuwuGup25eRv5AdgBQB2jLovgzwrpXh/wAN6dEohiEOnaZbKFAVRj6BR3Y/zqW0
+0Fftker65Ol9qvJjwP3VsCPuxg9D6t1P6VqWenWcWpXl5jM8g/eTyHLBR/CD2X2r4U/aM/a9s/Cl
+zP4A+Fu3xD42lbyJLqEeZHZueNqgffkz26CgD0v9qr4z+EfAH7NnifwtPq0L+K9Y094LCyhbdKC4
+wXYD7qgE8mvy6+G1t8Xvij8GrH4R/DrS7u30OC+kuNXv4p2jimaQ8CVuAFUfw8k16Vrn7O/iDTv2
+cPFHxs+Out6kdcmg36fpbT/6RJM5+TzmP3RyPkHb0r9Hv2dfDWn+GP2WvDk0ehWGg3Wq2kd/dWlo
+mERpEGOTyTgDk980AfJfgT9gvw9Y2qXHxB8Q3mrX4UM1lp/7qIe245Y/pXvFj8IfhL8PtPjGleBN
+J80tgXFxD58pPrlsmvpW52yRPJgrJ3Y1434xu2Z/nlCpFGx2heT7igD5d+NHjez0DyrTS4obRp0I
+EccP7okD26fWvzz8W+KY9av5oLyyhWRW4mRRkV9HfGTW3l1ZsT27W8qmKFN2594OSSOwII/Gvja6
+DnVZg+d4Yg5oAa6Wqo4jkmkk42naAvfPfPpVnbtniXGdo5qnEu66A/2qsl/3srgnjpQA6efdIVXp
+3NZ5znjpUjdCT1NRnpQA5QcA5qRMbwDwM8/hTegqRVb7PNIFyqLgn0zxQBVYlnLHqTk0lFOVSzhR
+1JoAbRWrHpVw2zcBhhnI6gVmMhWRlPVTg0ANooooAkSaaI/u5ZI/91iKj6n1NFSKhPPY96AGd/Sk
+qw0bBV67T0qEqR1zmgBKTvRRQAU5Qxb5VLH6V6HpFgieFBdCz05QVy881uJW49NxIH4CuNvdTvrm
+Z1kunaMHAVFCLj6KAKALFjoOpagu6GCJIs4aaedYkX6liK6W08K6JbOJ9e8X6BbQKw3QWbPdSsPQ
+BBj8zXAZJ65J+tJnBzQB9ozeM9C1f4HW+k6RZ2/hnwxp4KWX2uTySW/imYfxlvQZNfJniO9tb3xL
+K1k5ktUG1JCu3fj+LB6ZrInurm6cNcTyzEdN7E4+npUSKXlVFGWYgAUAfqt+wN4Q3aLPrUkfzzS4
+U47E/wCAFfuf4Ys/J0mBACMKOK/NT9izwkNL+C+ir5QVmUMePYCv1O0a2C28Yx0FAGmUxKB6Crkd
+vIY9204xUZGZ29M1p28pWIIVzQBBHFlula9rZPM2ADj1xVqx08zy72GATnFdxZ6cqKPloAyrLSwi
+g7a6KGyUAfLWjFbKqjgGrqxAdhQBRS1XI4/SrAtxjpVwADoKWgDP+zDOcU02y+laVJgUAZRtFPb9
+KjNmp7VrHFMOM0AZBsge36VGbFe6/pWwcYpuRQBhtp6Z+5Vd9OjOflroWx7VCdvtQBzb6ZGf4f0q
+k+jxnPyCurbbUTbc9qAOPfRk5+SqL6RjOM13LBapS7Mds0AcU+luM4/lVJ7OROq8V2j7MdqoShMH
+OKAORaLHaomiHPFb8yRmstwAxGaAM1oeelQNEM9K02Aquw70AZjQA9s1A9uPStRlHWoiB9aAMhrY
+c8VUkthk8VuMvBqs6jFAHOyW3tVN7fnpXROgJNUpIx6UAc/JB7VReD2ronjGaqvHx0oA517fviq7
+2/1rfePnOBVWRBQBz7wcnIqq0Psa35Ix6d6pvFQBiPFjtVZojWy6deOfeqrR57AUAZDRe1QtHWu0
+ftVd4/agDxfTtK0rTdV1HWLezt4bq9ZWvLgR/PKVGF3HuMCvhb9u79pC98NeENO+EngfU47W9uov
+tGr3lsSsyK/8APYH+VfccHiDTZvh7DqySrc6dLaiePa2AyMu4Nn6Gvwe1mw1D9oD/go1qGn6Y0ss
+Or66Ykk6iG1jO0t9Aik0AfY/7BXwYSHQ774w+ILYtfXTNbaGJVyVjziWbn+8flB9AfWv0wubuGCC
+SeeREhQZYngYFY/hXQtE0Dwbo/hvSYk0/SdNs0giBGAqov8APvX5s/tT/tGat4r8dt8FvhFJcX17
+cXH2TULux5aZiceTGR2/vNQBf/aD/ad8QeMPGs3wd+Bi3Oo6jdSm3vNTs+XOeGjjPYDu9esfs8fs
+paR8LYLfxN4sWDX/AB/Mu+SaT547EnkrHnq3q/5V0P7N37N+i/BzwJBq2qQxah4+voQ1/euMi2zz
+5UZ7D1Pc19J6l4htbPUls4kk1LV5E/d2kQyx/wBonoq+5oA+F/2yNSk8U/Ff4RfB+xmZjrOsxzX8
+X/TMMAM+2Cx/CvuC3gistDtrW3CpBDEscarwFUDAH5CvzyiTWPG//Bb5W1A28o8Maa0pSIZSEiLA
+XJ6ndKOeK+69d8T6BoOjyXevaxYaTAi5MlzOsa4/E0AaF6REjSPLiJugzyK8I8aXVnPDqUsjzQ3S
+kRDg4depxXHeIv2s/gnpy3lrJ4lk1SZeIzYWzyKSP9rGMV4H4m/ah+G+rWFxDYXertMRmAy2RAVs
+8g+1AHmnxH0m1t/DuravaxO9lKfODTKdysRyeen0r47e1uHtVvpATBNKyrJ2ZhgkfhkV7j4/+JEP
+irwIbdJogS+HtxuGRnhjnrXg4ncWiRF2MaElVJ4BPXFACxKEbdnqCarFj8w9al3EK3oExVbPNADi
+crTQOfWhsYoUc0ASVpbY/wDhCm2oTcS3ZYsSMBEQceucyf8A6+2bULdRQA3qa9P0Lwpp9x4FGpXg
+c3MsmIgGxhR14rzONd0yj1Ne7L/o3hbT7VSdqRAn6nr/AFoA5a6tTbNIIPmITant/kn9K4DUbc22
+oMNpVWGVJ/iHrXrUFu1zKEAyxPpzk8D+dcd47hgh8Q26RHGIQm3PQLxQBwtFFFAB3rrbXTM3Nmkf
+E7kMgyDwOpIPrXJrzIv1r2bSY7K+tjfSCIXphVIVycALjkehP8qAOL1WySFRwFPcDFcnMMMa9E1q
+GXaZChDZwoUVwF3FLFKBJG6E/wB5SM0AU6ejFJVYBSQc4YZFMpcHGcHFAG+dU1C6sRAzRrbA58uN
+dij8BWXcxOJHkbkscnA70WUqx3eJM7WGDx0q/IwllAQ5UnuKANnwr4Xl1vfcyooskbazEnLH2rI8
+R6dHpfiqa0hXbEFDKM56ivorw3p8Fn4HtQqqokiLMF7GvJfGOiPc30mpxTphIPnQj5jgn+lAHmVd
+D4UsTqfxI0SyA3ebdpkewOf6Vz1ew/ArSTq/7R+hw7dwR9x/MD+tAH9EP7NOgix+GukRBMbLZc8d
+yM19yWMO21zjtivNf2cfh9pGo/CC1vhq2b1CUmsUjw0QH3Tk9QRz0r3bWdKt9HvPs0M5lGOjLgj/
+ABoA5dVJkP1rf0+zM0g4+X+dULe33zZ7ZrttNhVFUYFAGzYWapGvFdHFGFWs6EgKMYq2LhVHJoA0
+FxUm4VktexqOWA/GoG1SBesg/OgDd3Cguo71zD65aqeZB+dUJvE1rGvEgJ9jQB2LTYqBrgA9a8+m
+8WIchQ1ZsvihznaCPqaAPTGu0HeoWvVHcV5W/iKZujAfjVVtenJ/1q0AesNfp3cVC2op/eFeUHXJ
+iOZhUba5Lj/Wj86APVW1JP7wqu2qRjuK8rbW3PWYVA2sk9Zz+dAHqjaqmD8wqu2rKM/MK8rbWFwc
+zH86hOrp/wA9CfxoA9Rk1cdmGKoSauhJAavOjqsf9/8AWmnVY/7360Ad42rD/IqnJqRbpXGHVY/7
+1RNq0f8AeoA61rwknLH6VA1wPU1yh1Zcfe/Wozqq/wB6gDqzPnvUZmB781y39qr/AHv1pp1Vf71A
+HTNMPWojMPWuaOqIT979aYdSHXdQB0TTLjrUDzA55zXPNqAJ+9URv1x96gDbeUc81WaUfhWO18M9
+c1E16vY0AajuOtVZJBis5rweuartdg96AL7MCSaqSMM1VN0MfezUDXAz1oAsMarNjFRNOPUVC0wo
+ASQAmoCmaVpMk81GZOOtAEbLxioGH409nH/16jZqAPz51DUW0D/gmfBqlvI7XEHgqERAdS7W6gY/
+E14D+wv8GdQ8O6brPxN8UafLZanqC/ZdKjuU2usP3pJMHpuOB9Aa+gb7/lHz4e/7AFh/6DHXtujf
+8iNZf9cB/KgD4a/bC/aQl8MwS/C/wHdk+IrxNup3Vuctao3AjUj/AJaN+grpP2Rv2eoPh94Pj+If
+jK2E3jbVIvMgjnGTYRNzjn/lo3Un8K/Pfxf/AMpL73/sb4//AEatfukf+QF/wA0AUL/X7nUtSn0j
+QAvnIALq8YZjt8/zfHQfnUtnbaT4a0G+upJwjBTJdXty43uQOWZj/LoKwvh9/wAizP8A9f0v/oZr
+zH9p/wD5NL8Zf9ezfzoA/NeH46XPhT9t34r+MfDdtJruqa28lnpPkDcjtvUKx9R8ucDrXdaD+zb8
+b/jbrZ8TfFTX7zQbSU70ivCWlKnnCRDhB9a+e/2bv+Tz/BX/AF9/0NfvXq3/ACHpP9wfyoA+INH/
+AGRvg34V0pZNQ0+/8R3aAbpb6c7Sf91cCuA8Tp4J8F6p9i0bwN4djbzNkbfYFZif+BdvevtjVv8A
+Uzf7wr4e+KP/ACVW1/3B/wChUAfOXxD8b2d/YhNS8FaAkRU4njtfs79emB3r5w1A6bIfMsYZ4Azf
+ddgQB7V7d8Y/+PaH/eNeAj/j2T6/1oAR+Eb0zUFSt/qvxNRjqKAGnpSpncaRulKnT8aAHn7pqJjz
+Uh+7+NRH71ACpndkde1b8XiLUowqySeaoXADj2rHtf8Aj6FPuP8AWUAeneH/ABjplvKZL5GSRUz0
+4J7YrzbVb+TUtduLyQkmRywB7DJ4qiP4vrSN1oAbRRRQBraXpN5qN3AlvbyTGWYRRADh344/UfnX
+6HfCH9kPxfrc1l/wk9vJoQlA8hJxy+4Y/CvkD4V/8j54U/7CS/8Aoxa/ozu/+Rc8I/8AXIfyFAHn
+Hw+/Zt+H3hPQpvCWo+EtE1W+n8uT7XeKshR16nkHrXb658K/h1qvj3TdP1DwB4Qe2tYxuMltGwkA
+PT7tdq//ACMy/wC8P5V534k/5GkfU0Acr8Yf2TP2cfizp1tqmmeE7LwhPa/upptPRbUsfcLwa/Nz
+4pfsNS6BDfXHgtL3VbOAF1Jk+cj6dD+FfqFaf8iPf/79d3r/APyK2n/9g4/yoA/nh0z4C+Obvwfr
+Gq6TpaapJZyGKa0hf/SFx1Ow815ra6UzeNIrK4tZLSRW2yQyLtZSOoOelfqn8F/+T5viV/18L/M1
+8SfGj/k+fxJ/1+0ATqsVh4fghVcPjGK4TULFblL2NcKHRlH4iu51Prb/AErmT99vxoA+aXRo5njY
+YZWII9xX1f8AshaR/aP7SEUxXcsZTt7k/wBK+XNT/wCRivv+u7/zNfaH7Ef/ACXab/fH/oJoA/oW
++GomsPD9s0LvE20coxBr3CK5muQrTSySkDq7E1434J/5F+3/ANwfyr1yy/1QoA6O1nWJQCDW3Fqy
+RgfK3HtXNR/0qT0oA6VvEMgGFXH1NZ83iC5P/LUL9Kwn+7WRc96AOgl1yUk5uG/Os6XWM9ZWb8a5
+1/4vpVJ+v4UAdBJrA9aoyawexrBkqo/Q0Abkmrt13Gqb6q+fvmsR+9V360Abh1Vv75qM6q2PvnNc
+833vzplAHQnU267jUZ1RsferBbpUJ/rQBvPqbZ+/VdtTbP3zWK/3agfvQBuHUm/vH86Z/aLZ+8aw
+zTB0/CgDolv2J+8acb44+8awV+/Uh6H60AabagR/EahOoHP3qyXqu39KANw6icfeqM6ic/fNYjda
+jP3xQBvf2if71RvqTdmNYh+9Ub9DQBtjUm/v046m3941ztHf8KAN46m2fvGozqh/vGsF/uCoj1oA
+6A6of71RnVDnrWBUTf1oA6A6pz1ph1Pn71YDdTUR/wBYaAOjOp9fmqP+08n71c+e9MoA6P8AtEHv
+Sf2gPWueHf6Uo6D60Abxvx/epn24H+KsP0pB2oA2zej1pn2xf71Yz9RTDQB//9k=
+
+--sp9pxLEwghDaJRixlkdZ=_QAHPr6hfigLP--
diff --git a/test/unit/aaa_string_test.rb b/test/unit/aaa_string_test.rb
index 68fe0e1ed..7aba4ebf3 100644
--- a/test/unit/aaa_string_test.rb
+++ b/test/unit/aaa_string_test.rb
@@ -552,7 +552,8 @@ Men-----------------------'
assert_equal(result, html.html2html_strict)
html = '
https://www.facebook.com/test
'
- result = '