diff --git a/install.sh b/install.sh
index 0f84dc8..61525ec 100755
--- a/install.sh
+++ b/install.sh
@@ -131,12 +131,18 @@ then
fi
fi
-echo "Select installation type:"
+echo "Select installation type: (default: [1] Complete installation)"
echo "[1] Complete installation (manager, webinterface, worker)"
echo "[2] Management installation (manager, webinterface)"
echo "[3] Worker installation (worker only)"
+echo "Note: When there is a default option available pressing enter will select it automatically."
read INSTALL_TYPE
+if [ -z "$INSTALL_TYPE" ]
+then
+ INSTALL_TYPE="1"
+ echo "Performing complete installation"
+fi
check_requirements $INSTALL_TYPE
@@ -228,10 +234,16 @@ then
echo "Setting password to default value"
fi
- echo "Should we take care of rabbitmq.config file? [yes/no]"
+ echo "Should we take care of rabbitmq.config file? [yes/no] (default: yes)"
echo "Select no if you already have an existing rabbitmq setup."
read CREATE_RMQ_CONFIG
+ if [ -z "$CREATE_RMQ_CONFIG" ]
+ then
+ CREATE_RMQ_CONFIG="yes"
+ echo "Creating default rabbitmq configuration file"
+ fi
+
if [ "$CREATE_RMQ_CONFIG" = "yes" ] || [ "$CREATE_RMQ_CONFIG" = "y" ];
then
if [ ! -d /etc/rabbitmq ];
@@ -295,7 +307,7 @@ then
cp scripts/renew_cert.sh $SECPI_PATH
# generate ca cert
- openssl req -config $CERT_PATH/ca/openssl.cnf -x509 -newkey rsa:2048 -days 365 -out $CERT_PATH/ca/cacert.pem -keyout $CERT_PATH/ca/private/cakey.pem -outform PEM -subj /CN=$CA_DOMAIN/ -nodes
+ openssl req -config $CERT_PATH/ca/openssl.cnf -x509 -newkey rsa:2048 -days 3650 -out $CERT_PATH/ca/cacert.pem -keyout $CERT_PATH/ca/private/cakey.pem -outform PEM -subj /CN=$CA_DOMAIN/ -nodes
# secure ca key
chmod 600 $CERT_PATH/ca/private
diff --git a/manager/dropbox_dropper.py b/manager/dropbox_dropper.py
index e2b55ef..278c9bb 100644
--- a/manager/dropbox_dropper.py
+++ b/manager/dropbox_dropper.py
@@ -36,8 +36,9 @@ def notify(self, info):
#self.dbx.files_create_folder(dropbox_dir) # shouldn't be necessary, automatically created
for file in os.listdir(latest_subdir):
if os.path.isfile("%s/%s" % (latest_subdir, file)):
- f = open("%s/%s" % (latest_subdir, file), "rb")
- data = f.read()
+ with open("%s/%s" % (latest_subdir, file), "rb") as f:
+ data = f.read()
+
try:
logging.info("Dropbox: Trying to upload file %s to %s" % (file, dropbox_dir))
res = self.dbx.files_upload(data, "%s/%s" % (dropbox_dir, file))
@@ -46,7 +47,6 @@ def notify(self, info):
logging.error("Dropbox: API error: %s" % d)
except Exception as e: # currently this catches wrong authorization, we should change this
logging.error("Dropbox: Wasn't able to upload file: %s" % e)
- f.close()
else:
logging.error("Dropbox: Wasn't able to notify because there was an initialization error")
diff --git a/manager/mailer.py b/manager/mailer.py
index 4a13510..32ea287 100644
--- a/manager/mailer.py
+++ b/manager/mailer.py
@@ -1,11 +1,15 @@
-import logging
import os
+import logging
import smtplib
-
-from email.mime.application import MIMEApplication
+import mimetypes
from email.mime.multipart import MIMEMultipart
+from email.mime.nonmultipart import MIMENonMultipart
+from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
+from email.mime.image import MIMEImage
+from email.mime.audio import MIMEAudio
from tools.notifier import Notifier
+from tools.utils import str_to_value
class Mailer(Notifier):
@@ -20,6 +24,7 @@ def __init__(self, id, params):
self.smtp_user = params["smtp_user"]
self.smtp_pass = params["smtp_pass"]
self.smtp_security = params["smtp_security"]
+ self.unzip_attachments = str_to_value(params.get("unzip_attachments", False))
except KeyError as ke: # if config parameters are missing
logging.error("Mailer: Wasn't able to initialize the notifier, it seems there is a config parameter missing: %s" % ke)
self.corrupted = True
@@ -38,7 +43,7 @@ def notify(self, info):
self.message["From"] = self.params["sender"]
self.message["To"] = self.params["recipient"]
self.message["Subject"] = self.params.get("subject", "SecPi Alarm")
- self.message.attach(MIMEText(self.params.get("text", "Your SecPi raised an alarm. Please check the attached files."), "plain"))
+ self.message.attach(MIMEText(self.params.get("text", "Your SecPi raised an alarm. Please check the attached files."), "plain", 'utf-8'))
info_str = "Recieved alarm on sensor %s from worker %s: %s"%(info['sensor'], info['worker'], info['message'])
self.message.attach(MIMEText(info_str, "plain"))
@@ -73,18 +78,65 @@ def prepare_mail_attachments(self):
logging.debug("Mailer: Will look into %s for data" % latest_subdir)
#then iterate through it and attach all the files to the mail
for file in os.listdir(latest_subdir):
+ filepath = "%s/%s" % (latest_subdir, file)
# check if it really is a file
- if os.path.isfile("%s/%s" % (latest_subdir, file)):
- f = open("%s/%s" % (latest_subdir, file), "rb")
- att = MIMEApplication(f.read())
- att.add_header('Content-Disposition','attachment; filename="%s"' % file)
- f.close()
- self.message.attach(att)
- logging.debug("Mailer: Attached file '%s' to message" % file)
+ if os.path.isfile(filepath):
+
+ # Add each file in zipfile as separate attachment
+ if self.unzip_attachments and file.endswith('.zip'):
+ self.prepare_expand_zip_attachment(filepath)
+
+ # Add file as a whole (default)
+ else:
+ with open(filepath, "rb") as f:
+ self.prepare_add_attachment(file, f.read())
+
else:
logging.debug("Mailer: %s is not a file" % file)
# TODO: maybe log something if there are no files?
+ def prepare_add_attachment(self, filename, payload):
+ """Add single attachment to current mail message"""
+
+ # Determine content type
+ ctype, encoding = mimetypes.guess_type(filename, strict=False)
+ maintype, subtype = ctype.split('/', 1)
+
+ # Create proper MIME part by maintype
+ if maintype == 'application' and subtype in ['xml', 'json']:
+ mimepart = MIMENonMultipart(maintype, subtype, charset='utf-8')
+ mimepart.set_payload(payload.encode('utf-8'), 'utf-8')
+
+ elif maintype == 'text':
+ mimepart = MIMEText(payload.encode('utf-8'), _subtype=subtype, _charset='utf-8')
+
+ elif maintype == 'image':
+ mimepart = MIMEImage(payload, _subtype=subtype)
+
+ elif maintype == 'audio':
+ mimepart = MIMEAudio(payload, _subtype=subtype)
+
+ else:
+ # Encode the payload using Base64 (Content-Transfer-Encoding)
+ mimepart = MIMEApplication(payload)
+
+ # Attach MIME part to message
+ mimepart.add_header('Content-Disposition','attachment; filename="%s"' % filename)
+ self.message.attach(mimepart)
+
+ logging.debug("Mailer: Attached file '%s' to message" % filename)
+
+ def prepare_expand_zip_attachment(self, filepath):
+ """Decode zip file and add each containing file as attachment to current mail message"""
+ logging.debug("Mailer: Decoding zip file '%s' as requested" % filepath)
+ import zipfile
+ with zipfile.ZipFile(filepath) as zip:
+ filenames = zip.namelist()
+
+ for filename in filenames:
+ payload = zip.read(filename)
+ self.prepare_add_attachment(filename, payload)
+
def send_mail_starttls(self):
logging.debug("Mailer: Trying to send mail with STARTTLS")
try:
diff --git a/manager/manager.py b/manager/manager.py
index dc33e08..94ebb36 100644
--- a/manager/manager.py
+++ b/manager/manager.py
@@ -108,7 +108,10 @@ def connect(self):
connected = True
logging.info("Connection to rabbitmq service established")
except pika.exceptions.AMQPConnectionError as pe: # if connection can't be established
- logging.error("Wasn't able to connect to rabbitmq service: %s" % pe)
+ if "The AMQP connection was closed" in repr(pe):
+ logging.error("Wasn't able to connect to the rabbitmq service, please check if the rabbitmq service is reachable and running")
+ else:
+ logging.error("Wasn't able to connect to the rabbitmq service: %s" % repr(pe))
time.sleep(30)
#define exchange
@@ -239,9 +242,9 @@ def got_data(self, ch, method, properties, body):
newFile_bytes = bytearray(body)
if newFile_bytes: #only write data when body is not empty
try:
- newFile = open("%s/%s.zip" % (self.current_alarm_dir, hashlib.md5(newFile_bytes).hexdigest()), "wb")
- newFile.write(newFile_bytes)
- logging.info("Data written")
+ with open("%s/%s.zip" % (self.current_alarm_dir, hashlib.md5(newFile_bytes).hexdigest()), "wb") as newFile:
+ newFile.write(newFile_bytes)
+ logging.info("Data written")
except IOError as ie: # File can't be written, e.g. permissions wrong, directory doesn't exist
logging.exception("Wasn't able to write received data: %s" % ie)
self.received_data_counter += 1
@@ -356,7 +359,7 @@ def setup_notifiers(self):
# timeout thread which sends the received data from workers
def notify(self, info):
- for i in range(0, self.data_timeout):
+ for i in xrange(0, self.data_timeout):
if self.received_data_counter < self.num_of_workers: #not all data here yet
logging.debug("Waiting for data from workers: data counter: %d, #workers: %d" % (self.received_data_counter, self.num_of_workers))
time.sleep(1)
@@ -377,7 +380,7 @@ def notify(self, info):
# go into holddown state, while in this state subsequent alarms are interpreted as one alarm
def holddown(self):
self.holddown_state = True
- for i in range(0, self.holddown_timer):
+ for i in xrange(0, self.holddown_timer):
time.sleep(1)
logging.debug("Holddown is over")
self.holddown_state = False
diff --git a/manager/slack.py b/manager/slack.py
new file mode 100644
index 0000000..aed1e7b
--- /dev/null
+++ b/manager/slack.py
@@ -0,0 +1,55 @@
+import logging
+
+from slacker import Slacker
+
+from tools.notifier import Notifier
+
+class SlackNotifier(Notifier):
+
+ def __init__(self, id, params):
+ super(SlackNotifier, self).__init__(id, params)
+ if(not 'bot_token' in params or not 'channel' in params):
+ self.corrupted = True
+ logging.error("Slack: Token or channel name missing!")
+ return
+
+
+ def notify(self, info):
+ if(not self.corrupted):
+ try:
+ logging.debug("Sending Slack notification!")
+
+ channel_name = self.params['channel']
+ slack = Slacker(self.params['bot_token'])
+
+ # groups are private chats
+ channels = slack.groups.list(1) # 1 --> exclude archived
+ channel = [c for c in channels.body['groups'] if c['name'] == channel_name]
+
+ if(len(channel)>0):
+ # we got a channel
+ channel_id = channel[0]['id']
+ logging.debug("Got existing channel!")
+ else:
+ # if not exists, create it
+ logging.debug("No channel found, creating one!")
+ new_channel_req = slack.groups.create(channel_name)
+
+ channel_id = new_channel_req.body['group']['id']
+
+ if(channel_id!=None):
+ logging.debug("Found channel: %s"%channel_id)
+ info_str = "Recieved alarm on sensor %s from worker %s: %s"%(info['sensor'], info['worker'], info['message'])
+ slack.chat.post_message(channel_name, info_str)
+
+ else:
+ logging.error("No channel found!")
+ except KeyError as ke:
+ logging.error("Error in Slack Notifier: %s"%ke)
+
+ else:
+ logging.error("Slack Notifier corrupted! No token or channel name given as parameter.")
+
+ def cleanup(self):
+ logging.debug("Slack Notifier: No cleanup necessary at the moment.")
+
\ No newline at end of file
diff --git a/manager/spark.py b/manager/spark.py
new file mode 100644
index 0000000..311cd56
--- /dev/null
+++ b/manager/spark.py
@@ -0,0 +1,59 @@
+import logging
+import requests
+import requests.exceptions
+
+from tools.notifier import Notifier
+
+class SparkNotifier(Notifier):
+
+ def __init__(self, id, params):
+ super(SparkNotifier, self).__init__(id, params)
+ if(not 'personal_token' in params or not 'room' in params):
+ self.corrupted = True
+ logging.error("Token or room name missing!")
+ return
+
+
+ def notify(self, info):
+ if(not self.corrupted):
+ try:
+ logging.debug("Sending Cisco Spark notification!")
+
+ room_name = self.params['room']
+ auth_header = {'Authorization': 'Bearer %s'%self.params['personal_token']}
+
+ # get room id
+ rooms_req = requests.get('https://api.ciscospark.com/v1/rooms', headers=auth_header)
+ rooms = rooms_req.json()
+ room = [r for r in rooms['items'] if r['title'] == room_name]
+
+ if(len(room)>0):
+ # we got a room
+ room_id = room[0]['id']
+ logging.debug("Got existing room!")
+ else:
+ # if not exists, create it
+ logging.debug("No room found, creating one!")
+ new_room_req = requests.post('https://api.ciscospark.com/v1/rooms', headers=auth_header, data={'title': room_name})
+ new_room = new_room_req.json()
+
+ room_id = new_room['id']
+
+ if(room_id!=None):
+ logging.debug("Found room: %s"%room_id)
+ info_str = "Recieved alarm on sensor %s from worker %s: %s"%(info['sensor'], info['worker'], info['message'])
+ noti_req = requests.post('https://api.ciscospark.com/v1/messages', headers=auth_header, data={'roomId': room_id, 'text': info_str})
+
+ else:
+ logging.error("No room found!")
+ except RequestException as ce:
+ logging.error("Error in Spark Notifier: %s"%ce)
+ except KeyError as ke:
+ logging.error("Error in Spark Notifier: %s"%ke)
+
+ else:
+ logging.error("Cisco Spark Notifier corrupted! No authorization code or room name given as parameter.")
+
+ def cleanup(self):
+ logging.debug("Cisco Spark Notifier: No cleanup necessary at the moment.")
+
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index a103413..869d794 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,4 +9,6 @@ tweepy
dropbox
logging
netifaces
-python-gsmmodem
\ No newline at end of file
+python-gsmmodem
+slacker
+pyping
\ No newline at end of file
diff --git a/stuff/secpi-logo.ai b/stuff/secpi-logo.ai
new file mode 100644
index 0000000..736208c
--- /dev/null
+++ b/stuff/secpi-logo.ai
@@ -0,0 +1,1624 @@
+%PDF-1.5
%âãÏÓ
+1 0 obj
<>/OCGs[5 0 R 6 0 R 26 0 R 27 0 R 47 0 R 48 0 R 49 0 R 84 0 R 85 0 R 86 0 R 121 0 R 122 0 R 123 0 R 124 0 R 161 0 R 162 0 R 163 0 R 165 0 R 164 0 R 166 0 R 205 0 R 206 0 R 207 0 R 209 0 R 208 0 R 210 0 R 249 0 R 250 0 R 251 0 R 252 0 R 254 0 R 253 0 R 255 0 R 297 0 R 301 0 R 302 0 R 298 0 R 299 0 R 300 0 R 303 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<>stream
+
+
+
+
+ application/pdf
+
+
+ Web
+
+
+
+
+ Adobe Illustrator CS5
+ 2016-03-18T11:55:32+01:00
+ 2016-03-26T13:11:15+01:00
+ 2016-03-26T13:11:15+01:00
+
+
+
+ 248
+ 256
+ JPEG
+ /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAD4AwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FUi82earXQbHkaSX0oItoPE/zN/kj8cVee+VvP97Y6pK+oyvcWl2/K4ruUc7c
0HgBtQdsVeuQzRTRJNC4kikAZHU1BB3BBGKr8VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir
sVdirsVdirsVdirsVdirsVdirsVSfzP5ms9BsDPLR7h6i2t60Lt/BR3OKvEtX1e91S9ku7uQyTSH
c9gOyqOwGKoNTQ4qzPyL53bSJBZXpLabI2zbkwsf2gP5T3H0/NV65HJHLGskbB43AZHU1BB3BBGK
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
+
+
+
+
+
+ proof:pdf
+ uuid:65E6390686CF11DBA6E2D887CEACB407
+ xmp.did:F77F1174072068118083840C9FA05347
+ uuid:ecdbaf01-cab0-b64d-8760-0d26b8deaa69
+
+ uuid:72b1533f-9e90-064f-87a5-4345918e86e3
+ xmp.did:FD7F11740720681188C6F0AB0253E170
+ uuid:65E6390686CF11DBA6E2D887CEACB407
+ proof:pdf
+
+
+
+
+ saved
+ xmp.iid:F77F1174072068118083840C9FA05347
+ 2016-03-18T11:55:32+01:00
+ Adobe Illustrator CS5
+ /
+
+
+
+
+
+ Web
+ Document
+
+
+ 1
+ False
+ False
+
+ 1024.000000
+ 1024.000000
+ Pixels
+
+
+
+
+ Helvetica-BoldOblique
+ Helvetica
+ Bold Oblique
+ TrueType
+ 9.0d3e2
+ False
+ Helvetica.dfont
+
+
+
+
+
+ Cyan
+ Magenta
+ Yellow
+ Black
+
+
+
+
+
+ Standard-Farbfeldgruppe
+ 0
+
+
+
+ Weiß
+ RGB
+ PROCESS
+ 255
+ 255
+ 255
+
+
+ Schwarz
+ RGB
+ PROCESS
+ 0
+ 0
+ 0
+
+
+ RGB Rot
+ RGB
+ PROCESS
+ 255
+ 0
+ 0
+
+
+ RGB Gelb
+ RGB
+ PROCESS
+ 255
+ 255
+ 0
+
+
+ RGB Grün
+ RGB
+ PROCESS
+ 0
+ 255
+ 0
+
+
+ RGB Cyan
+ RGB
+ PROCESS
+ 0
+ 255
+ 255
+
+
+ RGB Blau
+ RGB
+ PROCESS
+ 0
+ 0
+ 255
+
+
+ RGB Magenta
+ RGB
+ PROCESS
+ 255
+ 0
+ 255
+
+
+ R=193 G=39 B=45
+ RGB
+ PROCESS
+ 193
+ 39
+ 45
+
+
+ R=237 G=28 B=36
+ RGB
+ PROCESS
+ 237
+ 28
+ 36
+
+
+ R=241 G=90 B=36
+ RGB
+ PROCESS
+ 241
+ 90
+ 36
+
+
+ R=247 G=147 B=30
+ RGB
+ PROCESS
+ 247
+ 147
+ 30
+
+
+ R=251 G=176 B=59
+ RGB
+ PROCESS
+ 251
+ 176
+ 59
+
+
+ R=252 G=238 B=33
+ RGB
+ PROCESS
+ 252
+ 238
+ 33
+
+
+ R=217 G=224 B=33
+ RGB
+ PROCESS
+ 217
+ 224
+ 33
+
+
+ R=140 G=198 B=63
+ RGB
+ PROCESS
+ 140
+ 198
+ 63
+
+
+ R=57 G=181 B=74
+ RGB
+ PROCESS
+ 57
+ 181
+ 74
+
+
+ R=0 G=146 B=69
+ RGB
+ PROCESS
+ 0
+ 146
+ 69
+
+
+ R=0 G=104 B=55
+ RGB
+ PROCESS
+ 0
+ 104
+ 55
+
+
+ R=34 G=181 B=115
+ RGB
+ PROCESS
+ 34
+ 181
+ 115
+
+
+ R=0 G=169 B=157
+ RGB
+ PROCESS
+ 0
+ 169
+ 157
+
+
+ R=41 G=171 B=226
+ RGB
+ PROCESS
+ 41
+ 171
+ 226
+
+
+ R=0 G=113 B=188
+ RGB
+ PROCESS
+ 0
+ 113
+ 188
+
+
+ R=46 G=49 B=146
+ RGB
+ PROCESS
+ 46
+ 49
+ 146
+
+
+ R=27 G=20 B=100
+ RGB
+ PROCESS
+ 27
+ 20
+ 100
+
+
+ R=102 G=45 B=145
+ RGB
+ PROCESS
+ 102
+ 45
+ 145
+
+
+ R=147 G=39 B=143
+ RGB
+ PROCESS
+ 147
+ 39
+ 143
+
+
+ R=158 G=0 B=93
+ RGB
+ PROCESS
+ 158
+ 0
+ 93
+
+
+ R=212 G=20 B=90
+ RGB
+ PROCESS
+ 212
+ 20
+ 90
+
+
+ R=237 G=30 B=121
+ RGB
+ PROCESS
+ 237
+ 30
+ 121
+
+
+ R=199 G=178 B=153
+ RGB
+ PROCESS
+ 199
+ 178
+ 153
+
+
+ R=153 G=134 B=117
+ RGB
+ PROCESS
+ 153
+ 134
+ 117
+
+
+ R=115 G=99 B=87
+ RGB
+ PROCESS
+ 115
+ 99
+ 87
+
+
+ R=83 G=71 B=65
+ RGB
+ PROCESS
+ 83
+ 71
+ 65
+
+
+ R=198 G=156 B=109
+ RGB
+ PROCESS
+ 198
+ 156
+ 109
+
+
+ R=166 G=124 B=82
+ RGB
+ PROCESS
+ 166
+ 124
+ 82
+
+
+ R=140 G=98 B=57
+ RGB
+ PROCESS
+ 140
+ 98
+ 57
+
+
+ R=117 G=76 B=36
+ RGB
+ PROCESS
+ 117
+ 76
+ 36
+
+
+ R=96 G=56 B=19
+ RGB
+ PROCESS
+ 96
+ 56
+ 19
+
+
+ R=66 G=33 B=11
+ RGB
+ PROCESS
+ 66
+ 33
+ 11
+
+
+
+
+
+ Grautöne
+ 1
+
+
+
+ R=0 G=0 B=0
+ RGB
+ PROCESS
+ 0
+ 0
+ 0
+
+
+ R=26 G=26 B=26
+ RGB
+ PROCESS
+ 26
+ 26
+ 26
+
+
+ R=51 G=51 B=51
+ RGB
+ PROCESS
+ 51
+ 51
+ 51
+
+
+ R=77 G=77 B=77
+ RGB
+ PROCESS
+ 77
+ 77
+ 77
+
+
+ R=102 G=102 B=102
+ RGB
+ PROCESS
+ 102
+ 102
+ 102
+
+
+ R=128 G=128 B=128
+ RGB
+ PROCESS
+ 128
+ 128
+ 128
+
+
+ R=153 G=153 B=153
+ RGB
+ PROCESS
+ 153
+ 153
+ 153
+
+
+ R=179 G=179 B=179
+ RGB
+ PROCESS
+ 179
+ 179
+ 179
+
+
+ R=204 G=204 B=204
+ RGB
+ PROCESS
+ 204
+ 204
+ 204
+
+
+ R=230 G=230 B=230
+ RGB
+ PROCESS
+ 230
+ 230
+ 230
+
+
+ R=242 G=242 B=242
+ RGB
+ PROCESS
+ 242
+ 242
+ 242
+
+
+
+
+
+ Webfarbgruppe
+ 1
+
+
+
+ R=63 G=169 B=245
+ RGB
+ PROCESS
+ 63
+ 169
+ 245
+
+
+ R=122 G=201 B=67
+ RGB
+ PROCESS
+ 122
+ 201
+ 67
+
+
+ R=255 G=147 B=30
+ RGB
+ PROCESS
+ 255
+ 147
+ 30
+
+
+ R=255 G=29 B=37
+ RGB
+ PROCESS
+ 255
+ 29
+ 37
+
+
+ R=255 G=123 B=172
+ RGB
+ PROCESS
+ 255
+ 123
+ 172
+
+
+ R=189 G=204 B=212
+ RGB
+ PROCESS
+ 189
+ 204
+ 212
+
+
+
+
+
+
+
+
+ Adobe PDF library 9.90
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
endstream
endobj
3 0 obj
<>
endobj
8 0 obj
<>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text]/Properties<>/Shading<>>>/Thumb 311 0 R/TrimBox[0.0 0.0 1024.0 1024.0]/Type/Page>>
endobj
305 0 obj
<>stream
+H‰¬—Ko$Ç„ïý+úh¦YïÇu©…O²½ ëNÈ^CÒkèßû‹¬î™é¢/6,¢2§+«*322êé/ÏëÓ�ÏnýôÃóºüº¸ÕÞ…¸åãÏo?/[á§§?½¸õß–‹Ûÿ¤ÜÖß$Y©µ8Y÷¯²÷[ê�?õúö¾|úi}zùêÖo_×Ï?_–/¶»BŒÿX´c÷§ç¿>¿¬Îþ]_žÿ|;ΑSå}ͱðeùü#—zWôãŠÚ&9·ÖÌ‚Ö÷%º²¥°–^·¾z¹×Zò÷åѺ.>Å-¶¼–¶ÞÊBÝRlkŠ}sÜóû2{®Kômë1¯Á×Í•N.çsÄ>þïºT—ùíþMíeËÅ?Ä�=×¥5·ŸngivÆãÜ�ñ‰Ë¢qÁBnŽ»_ë’[ܼïc¡‡m9í‡Õÿ]—”ÜÖš¿}ó˜ËïR*• ½ÅØ›ÕíòèPncö®’ûTëþ¿„wk§ÿ<¼[ÿµÞNòëêíþV ¶“ã}¹ø-ý~Oÿ%´D¶Ãoù¿ÄÒ,ÝyO7OnËžïK „Bº¥øâÙ£Ürr©Þ²jëÕRzöž—œÂ�·šOòñ°ó}tÍß—¯´Ã—SC„£!>½Žd¾}#?úwýööË-uO¯¯ÊÛëß—˜Gûéo(y‹Á·5rÆÒ9Ðëûò‡—¿þñõŸËç×Ó>ñà–…ÙÌÑÛÆ
É}
+e+ %.QÁ7ø(¡®™Ëd,.Î9QÆr¶�bq[ÊñÁ†gò±X?³œh.š6eš WÛ<û¨p“‡ 9q<Ùo=±ÄYðf™D
+©ßl"L"°wJk¢ªÓ-b3b8§àmï2½°4ú[Ø›åÁÞoîJQáB*æÿ¹eö*«M¢ºäÞãF¤k\€ßû$oÍé;Bn¥ªO¶šiOÒ";ȱs£”—[·ïp¾pø<6• 'Š\™!˜ùËZ.D[pÜø‘åK7Âña‹²
+e³ËH8‡)‚£ߧÄÛŽy¥¤�´”èþ&¨¼/%ò%‡7à±c)£Ô7³l½ÔÝ.5lAELe«ÎŒ&»oÍ볇ðsu‚mêËZšÚ\@h›§Š…¶í�þº “G1H)K`ŠÂßÒòÝcS lá.E¥ª�Bdqö¢öª¡šj «�RåÉòPÄ%¥ìëOö•üÝÑI/„^[æ.†Î{$S˜$ƒå4ÞÿoÀœŽze ÜKcôÏ$ÿ5 /
|”Ãàö½›ÁPÂGf¨®ukBhTÞ„]Àå€É%€µÆIÓ¦©wAÖÄXVáR€o4}]I®©ŽÙ¯�90‹„JH‘·š”Z$�c€£RÔ¸j•ú`jÃM¤<“p&a&~&íƒ0i„I¹ R4F=ÿó(KÊ$KÚYÒ>È’%á$KÂY–”C–ì7ßeÉn=Ê’ Q9´H¼©’xR%öÉc¿/��vHŒªœÕþúu\2;gÔÕ¥‘¶àÊ‘zEØo(W€QÕ᳇f¾…�²êžª �]Cé™’ø9.´VR±g1+ °qÅ´3M–C}Œ‘hè(–˜=Ħ®{Œ¯ÂE§^Ѿ0rKkzÊä[XCÏûÔõÆàoËì¹.¡1 ¼�’™ ù´Ä¾M×VýœÅM¥[½-³‡Ì;o܃J`Û:.'?Ý]%ÙR9\Å&òìJÁ-=WœZ†îÕüÒr!P8(¹ÓJ‡MŒÉCŒ2�O3w(»Ã�Ž´”²ké–äÉCŒ†ÊivtD¢GâB4ª6ä`\ˆ‹25Ôëg[€U|y°QÁÔ?WMÉ;'¡X^¸É\™ÍA}µù8{„=ÊÊ·4˜6à˜b–H;Äžo¶ÒröºDWÜ×@YÉgêxz(‚RD¾íJ)ÆäåéL:;eŠšØŒ¦Ì
++d½xëp�]¿[“pëZ-C“‡Œó¹eŒ?`’ ¡Åd òâvÀ@Ï)Ää¹õ$¾å¡eÇaš‘(=¼`dhíHàa¿-³G´BÙýá }ÐY¢ØÕë%"©Ã™‚qÂÙ' ùfg›0¾Žzi:½q链E꣓©ý½FêݤN¶Tr_?ªFbð–é"ë$–”³0Èåì¹Ú|Óc.�&!1H´Ã†Œ¤Dºëf*''‡zÈÙ¼¸ Ê…š%fšOm�'ÏÛR¥ê£q�Qb𛙀›.µ+°
+…'×JšvÕŠ4”,åa°Û(>ªÒ ö°+IR½—ü*W®
8�MÍåñ~ÌÐXh$qˆÊ„Ú©H†ˆdê¨òä�pØGØÓ•Íc®6$Ð
+À
нõ1Âsò\M
{1lÐdJ¦Á“¾ÐKh-RÑ67ý®'›ÕqÇÆaæŠz$‚Ù¼lÐaþfåñÕ·°·U®*¬Í`=70–4B1�H+X;d{ÎXçNð!m£sˆ}�rƒMåÌÑ^/Ilؽ1Yj»Ùƒ´‘ø×Ã>*G¢u%yõAÏÒý\»géÙsµ§®HçX¢R©dUòT,@¯ç}‹l!&!èr'yM[*¡üÀØÈ7ij{{eާlL"èýbO ½µhM¡yô -R‘<êw.èK°gψ¡·�€RÅNÀ¤iœ¡=‰o$tüÄg›Õ¾šŠ¸ÛœHwp²õ«éz†-À2-—{Jg�j#‰,Û“DYGF 2zo$†Lñfbò‚¦àu_£—j…PôWÌm0ˆÕöѾZ“Ó÷DQJ”��TÂ$e�xYq,>Ùª){›>ìJÃî„*$Š“qµ&!_¢ôdX=;3J³M™½ÝEèÑĈ9ŽüðÎ:l¥ôìQM
+»…ûjÓZ¾O®©Q‰!µ¨cTc›÷E©”hT�‚rÈ¢@/7ø;Åd:|ˆ×Ùsµ M}_Jc¥˜\@Êõ1“àlkÓ`âhö@2!}ôŠ’Pd%›êë"\*U«¿Ù„˜<„@UÓSûš�{¤ž¢”ˆ„ªZ¨HŨef�^Oâ+Ž\ÔvÞhÝØÙž�R¦Mãh™³°óôÑ.z$[-¡¡M¼}|úK-”ôJ°x“‡pQÍöÕão´È¨;%r·‰1yˆAU’åp_�¨NM7Då-k�Ÿ¤¥ì“g”'ÚÌáf:GÐô—
å¥1;ô‘?–ãìQ½¡DáÇ3¾u.žš ú=~±àÙ¾ZDSCŒÖ>DaQÿ¨ùc8Ã&Àä!Dröd»AœŠ¹é\‡x�ê0ëCêä¹ð²J€ˆên/‰ N�GIä$°y7 r²0½çú݆U4\%´Üs¤¢æ‡šPìO Ç�&�΃l÷â ßq%7H"¨‘‚T~»Ùÿ&»lv+·• ¼×Sèó_äv|g™\¼Èì� ^Ø&&ÈÛ߯ŠÒ9Ǻ0`›šÝÕÕÕòëçŽPÑö ‡BN¦‘q{ü�4$Ì¢YL©eeVÕ‹îÇXJ Kê’AªG‰p—¿.?–°þ±ì†RGýõ5ð³=NDpOÿfáÅË—ïëÓË[\ÿ~[¿~_¿-ß|NT'á_›ÿõ»¯xz~‰ëóËý³¾<ÿºäõŸuùÁH—ÅuŠHp5U#hþcÙ@|á¿wþCâË`¨…Øûßà¯o|‡›/ÞµÄÄs¨ÝHN
+ö£GnhÎÁÃFŸ¤ž—°ob˜‚ÃöI¥Å¢“›úOrgó! °
^—�Ð ç�Ã#i¨8§Q$G-¸�³$*�‰xoãñ0ÏAS¥+lx‡ëÈT¥ÚV'£Æd¡Î�=L\›éô}=
+=º€îª�©ƒºÙ¨ë´eG•ªü…£ßñùù¯rIÜUe˜äõø#*ûa…Í”à¡�
>áÅ`ÞƒàPÄ9¡M„4@ñ÷5p€º®M%~ЛQ¦»&®:üŠšãô]’-v6$"ˆº´75D)Nl1øz ¨8¯J �Aß6²¢ïâ½CßÄE)N›Æ¼ßcJOˆ÷ mÂÕÂm
ì«6À§Ô¨Šp ™·¡‚æM¸:÷4Ir¢½t¹¼¸Ãe¢¸ø)N{˜ÁEŒ(ÂUZRÕ�ñF½$©È‡,³yc<ág“>ÑÖI"W¹oÂ^þ
y?ÇrâPQo+boVòðˆ‘wÔX˜BÀ–; ¯€ùâAÁøH:9æ!™œ]iÏ3eŠj²GSCwV•e=EzŠ;eiuÆysb�8ÜpU”³Y¬¡ûõ
+„ÄÖ9� “ ~�ž‡È`�IjöÎëZÑ-j±øHÍcB[’Ú�ø°Fb"öyFÖ8MN± bH<Œá¢Eç]«µ5(ðìpxp¥£>LÍbóÝ”p{·íð ¡æUçH7X›sZ¶„0ÔzÓ´PË„cÔ;ýÀtŸ°�|Ø¡šÇ¬cõ *‰Qñ%�FœÆfÉ á‹²£‹n6a "Îê7DMȃ}æT¦û;ƒ:¿¿NÖ+BI&uöè4ö]ÏÔùÛ.@d
+sE0‚ÆäÇóN�íÎý¶")Ëd6>˜k’Ñ‘ÓIü"'“Þ»nKåÉt>?s» ”f‚jÓ~Té�èMyÖ(µç¾þ°�ö,)E×’Œ?w±xœè%ÙjpŒ�Üg +"·N!4#¨ð�¤HI̳ž—Èý