From aa86b5344cf8d8afd2abbb56a52ed1f5eda66146 Mon Sep 17 00:00:00 2001
From: KF7EEL 1: Log into your Pi-Star device. Note: Link can be used only once. To run the script again, simply reload the page and paste a new command into the command line. DMR ID: ''' + str(i[0]) + ''': Error Your passphrase for ''' + str(i[0]) + ''': Copy and paste: ''' + str(gen_passphrase(int(i[0]))) + ''' Phonetically spelled: ''' + convert_nato(str(gen_passphrase(int(i[0])))) + ''' Your passphrase for ''' + str(i[0]) + ''': Copy and paste: ''' + str(gen_passphrase(int(i[0]))) + ''' Phonetically spelled: ''' + convert_nato(str(gen_passphrase(int(i[0])))) + ''' Your passphrase for ''' + str(i[0]) + ''': Copy and paste: ''' + legacy_passphrase + ''' Phonetically spelled: ''' + convert_nato(legacy_passphrase) + ''' Your passphrase for ''' + str(i[0]) + ''': Copy and paste: ''' + str(i[1]) + ''' Phonetically spelled: ''' + convert_nato(str(i[1])) + ''' Use this page to sync changes from RadioID.net with this system (such as a new DMR ID, name change, etc.). Updating your information from RadioID.net will overwrite any custom authentication passphrases, your city, and name in the database. Are you sure you want to continue? Sent email to: ' + u.email + ' Find user in "List Users", then click on the email link.' User ''' + str(user) + ''' has been enabled. User ''' + str(user) + ''' has been disabled. User ''' + str(user) + ''' changed to ''' + request.form.get('username') + '''. Changed email for user: ''' + str(user) + ''' to ''' + request.form.get('email') + ''' Changed notes for user: ''' + str(user) + '''. Changed password for user: ''' + str(user) + ''' Changed authentication settings for user: ''' + str(user) + ''' Deleted user: ''' + str(delete_user.username) + ''' User now Admin: ''' + str(request.args.get('callsign')) + ''' Admin now a user: ''' + str(request.args.get('callsign') ) + ''' User approved: ''' + str(request.args.get('callsign')) + ''' Email verified for: ''' + str(request.args.get('callsign')) + ''' Verify email - ''' + str(u.username) + ''' Give Admin role: ''' + str(u.username) + ''' Revert to User role: ''' + str(u.username) + ''' Email confirmed: ''' + str(u.email_confirmed_at) + ''' {DMR ID: Method, 2nd DMR ID: Method} Example: Flushed entire auth DB. Flushed auth DB for: ''' + request.args.get('portal_username') + ''' Flushed auth DB for: ''' + request.args.get('mmdvm_server') + ''' Flushed auth DB for: ''' + request.args.get('peer_ip') + ''' Flushed auth DB for: ''' + request.args.get('dmr_id') + ''' Flush auth log for: ''' + request.args.get('portal_username') + ''' Flush auth log for: ''' + request.args.get('dmr_id') + ''' Log for: ''' + g_arg + ''' Flush authentication log for server: ''' + request.args.get('mmdvm_server') + ''' Log for MMDVM server: ''' + request.args.get('mmdvm_server') + ''' Flush authentication log for IP: ''' + request.args.get('peer_ip') + ''' Log for IP address: ''' + request.args.get('peer_ip') + ''' Flush entire authentication log Un-registered authentication attempts Authentication log by DMR ID Currently active talkgroups. Updated every 2 minutes. DMR ID: ''' + str(i[0]) + ''' Redirecting in 3 seconds. Redirecting in 3 seconds. Redirecting in 3 seconds. Redirecting in 3 seconds.
-
-
-
-
-
-
-
-Pi-Star Instructions
-
2: Change to Read-Write mode of the device by issuing the command:rpi-rw
-
3a: Change to the root user by issuing the command:sudo su -
-
3b: Now type pwd and verify you get a return indicating you are in the /root directory. If you are in the wrong directory, it is because you're not following the instructions and syntax above! This is a show stopper, and your attempt to load the files correctly, will fail !
4: Issue one of the commands below for the chosen DMR ID:bash <(curl -s "''' + str(url) + '/get_script?dmr_id=' + str(i[0]) + '&number=' + str(link_num) + '''")
5: When asked for server ports, use the information above to populate the correct fields.
6: Reboot your Pi-Star device
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Updated your information.
'
- update_from_radioid(request.args.get('callsign'))
- else:
- content = '''
-Yes, update my information.
-
-'''
- return render_template('flask_user_layout.html', markup_content = Markup(content))
-
-
- @app.route('/email_user', methods=['POST', 'GET'])
- @roles_required('Admin')
- @login_required # User must be authenticated
- def email_user():
-
- if request.method == 'GET' and request.args.get('callsign'):
- content = '''
-Send email to user: ''' + request.args.get('callsign') + '''
-
-
-
-
-
-
-
- List/edit users:
-
-
-
- '''
- for i in u:
- u_list = u_list + '''
-Callsign
-Name
-Enabled
-DMR ID:Authentication
-Notes
-
-
-'''+ '\n'
- content = u_list + '''
- ''' + str(i.username) + '''
- ''' + str(i.first_name) + ' ' + str(i.last_name) + '''
- ''' + str(i.active) + '''
- ''' + str(i.dmr_ids) + '''
- ''' + str(i.notes) + '''
-Users waiting for approval:
-
-
-
- '''
- for i in u:
-## print(i.username)
-## print(i.initial_admin_approved)
- if i.initial_admin_approved == False:
- wait_list = wait_list+ '''
-Callsign
-Name
-Enabled
-DMR ID:Authentication
-
-
-'''+ '\n'
- content = wait_list + '''
- ''' + str(i.username) + '''
- ''' + str(i.first_name) + ' ' + str(i.last_name) + '''
- ''' + str(i.active) + '''
- ''' + str(i.dmr_ids) + '''
-
-
-
'
- content = '''
-
- '''
- for i in id_dict.items():
- print(i[1])
- if isinstance(i[1], int) == True:
- passphrase_list = passphrase_list + '''
-DMR ID
-Passphrase
-
- \n'''
- if i[1] == '':
- passphrase_list = passphrase_list + '''''' + str(i[0]) + '''
-''' + str(gen_passphrase(int(i[0]))) + '''
-
- \n'''
- if not isinstance(i[1], int) == True and i[1] != '':
- passphrase_list = passphrase_list + '''''' + str(i[0]) + '''
-''' + legacy_passphrase + '''
-
- \n'''
-
- passphrase_list = passphrase_list + '''' + str(i[0]) + '''
-''' + str(i[1]) + '''
-
-
-
-
-
-First Name
-Last Name
-
-
- ''' + u.first_name + '''
- ''' + u.last_name + '''
-
-
-
-City
-''' + u.city + '''
- Options for: ''' + u.username + '''
-
-
-
-
-
-
-
-
-
-
- ''' + confirm_link + '''
-
-
-
-
-
- ''' + role_link + '''
-
-
-
-
-
-
-
-
-
-
-
-
-
- Passphrase Authentication Method Key
-
-
-
-
-
-Calculated
-Legacy (config)
-Custom
-
-
-
-0 - default,
-
1-999 - new calculation''
-'passphrase'
-
{1234567: '', 134568: 0, 1234569: 'passphr8s3'}
-
-
-
-
-
-
-
-
-
'
-
- elif request.args.get('mmdvm_server') and not request.args.get('flush_db_mmdvm'):
- a = AuthLog.query.filter_by(server_name=request.args.get('mmdvm_server')).order_by(AuthLog.login_time.desc()).all()
- content = '''
-
- \n'''
- for i in a:
- if i.login_type == 'Attempt':
- content = content + '''
-
-
- DMR ID
-
-
- Portal Username
-
-
- Login IP
-
-
- Passphrase
-
-
- Server
-
-
- Time (UTC)
-
-
- Login Status
-
-
-'''
- if i.login_type == 'Confirmed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- if i.login_type == 'Failed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- content = content + ' ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-
'
-
- elif request.args.get('peer_ip') and not request.args.get('flush_db_ip'):
- a = AuthLog.query.filter_by(peer_ip=request.args.get('peer_ip')).order_by(AuthLog.login_time.desc()).all()
- content = '''
-
- \n'''
- for i in a:
- if i.login_type == 'Attempt':
- content = content + '''
-
-
- DMR ID
-
-
- Portal Username
-
-
- Login IP
-
-
- Passphrase
-
-
- Server
-
-
- Time (UTC)
-
-
- Login Status
-
-
-'''
- if i.login_type == 'Confirmed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + i.server_name + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- if i.login_type == 'Failed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + i.server_name + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- content = content + ' ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + i.server_name + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-
'
-
- else:
- #a = AuthLog.query.all()
-## a = AuthLog.query.order_by(AuthLog.login_time.desc()).limit(300).all()
- a = AuthLog.query.order_by(AuthLog.login_time.desc()).all()
- recent_list = []
-## r = AuthLog.query.order_by(AuthLog.login_dmr_id.desc()).all()
- content = '''
-
- \n'''
- for i in a:
- if i.login_type == 'Attempt':
- content = content + '''
-
-
- DMR ID
-
-
- Portal Username
-
-
- Login IP
-
-
- Passphrase
-
-
- Server
-
-
- Time (UTC)
-
-
- Login Status
-
-
-'''
- if i.login_type == 'Confirmed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + i.peer_ip + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- if i.login_type == 'Failed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + i.peer_ip + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- content = content + ' ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + i.peer_ip + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-
'
- return render_template('flask_user_layout.html', markup_content = Markup(content))
-
- @app.route('/user_tg')
- def tg_status():
- cu = current_user
- u = User.query.filter_by(username=cu.username).first()
- sl = ServerList.query.all()
- user_ids = ast.literal_eval(u.dmr_ids)
- content = '
- \n'''
- for i in a:
- if i.login_dmr_id not in recent_list:
- recent_list.append(i.login_dmr_id)
- if i.login_type == 'Attempt':
- content = content + '''
-
-
- DMR ID
-
-
- Portal Username
-
-
- Login IP
-
-
- Passphrase
-
-
- Server
-
-
- Time (UTC)
-
-
- Last Login Status
-
-
-'''
- if i.login_type == 'Confirmed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
- if i.login_type == 'Failed':
- content = content + '''
- ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-'''
-
- content = content + ' ''' + str(i.login_dmr_id) + '''
- ''' + i.portal_username + '''
- ''' + str(i.peer_ip) + '''
- ''' + i.login_auth_method + '''
- ''' + str(i.server_name) + '''
- ''' + str(i.login_time) + '''
- ''' + str(i.login_type) + '''
-
-
-
'''
-## except:
-## pass
-
-
-## #TS1
-## for tg in active_tgs[s.name][i[0]][1]['2']:
-## content = content + '''
-
-
-
-Server: ''' + str(s.name) + '''
-
-
-
-
-
-
-
-
-
-
-Timeslot 1
- ''' + str(active_tgs[s.name][ts[0]][0]['1'])[1:-1] + '''
-
-
-
-Timeslot 2
- ''' + str(active_tgs[s.name][ts[0]][1]['2'])[1:-1] + '''
- ''' + str(tg) + '''
-##'''
-## print(active_tgs[s.name][i[0]])
-## content = active_tgs[s.name][i[0]][1]['2']
-## content = 'hji'
-
- return render_template('flask_user_layout.html', markup_content = Markup(content))
-
-
- @app.route('/test')
- def test_peer():
- #user = User(
- # username='admin3',
- # email_confirmed_at=datetime.datetime.utcnow(),
- # password=user_manager.hash_password('admin'),
- # )
- #user.roles.append(Role(name='Admin'))
- #user.roles.append(Role(name='User'))
- #user.add_roles('Admin')
- #db.session.add(user)
- #db.session.commit()
- u = User.query.filter_by(username='admin').first()
- #u = Role.query.all()
-## u = User.query.filter(User.dmr_ids.contains('3153591')).first()
- #u = User.query.all()
-## #tu = User.query().all()
-#### print((tu.dmr_ids))
-#### #print(tu.dmr_ids)
-#### return str(tu.dmr_ids) #str(get_ids('kf7eel'))
-## login_passphrase = ast.literal_eval(u.dmr_ids)
-## print('|' + login_passphrase[3153591] + '|')
-## #print(u.dmr_ids)
-## #tu.dmr_ids = 'jkgfldj'
-## #db.session.commit()
-## return str(u.dmr_ids)
-## u = User.query.filter(User.dmr_ids.contains('3153591')).first()
-## #tu = User.query.all()
-## #tu = User.query().all()
-#### print((tu.dmr_ids))
-#### #print(tu.dmr_ids)
-#### return str(tu.dmr_ids) #str(get_ids('kf7eel'))
-## print(u)
-## login_passphrase = ast.literal_eval(u.dmr_ids)
-##
-## #tu.dmr_ids = 'jkgfldj'
-## #db.session.commit()
-## return str([u.is_active, login_passphrase[3153591]])
- #edit_user = User.query.filter(User.username == 'bob').first()
- #edit_user.active = False
-
- #db.session.commit()
- #print((current_user.has_roles('Admin')))
- #u.roles.append(Role(name='Admin'))
- #print((current_user.has_roles('Admin')))
- #db.session.commit()
- #db.session.add(u)
- #db.session.commit()
-## admin_role = UserRoles(
-## user_id=3,
-## role_id=1,
-## )
-## user_role = UserRoles(
-## user_id=3,
-## role_id=2,
-## )
-## db.session.add(user_role)
-## db.session.add(admin_role)
-## db.session.commit()
- #print(role)
-## for i in u:
-## print(i.username)
- #u = User.query.filter_by(username='kf7eel').first()
- #print(u.id)
- #u_role = UserRoles.query.filter_by(user_id=u.id).first()
- #if u_role.role_id == 2:
- # print('userhasjkdhfdsejksfdahjkdhjklhjkhjkl')
-## print(u.has_roles('Admin'))
- #u_role.role_id = 1
- #print(u)
- # for i in u:
- ##print(i.initial_admin_approved)
- #if not i.initial_admin_approved:
- #print(i.username)
- # print(i)
- #u_role = UserRoles.query.filter_by(id=2).first().role_id
- #u_role = 1
- # db.session.commit()
- #u_role = UserRoles.query.filter_by(id=u.id).first().role_id
- #print(u_role)
- #return str(u)
-## if not u.active:
-## flash('We come in peace', 'success')
-## content = 'hello'
- #add
-## burn_list = BurnList(
-## dmr_id=3153595,
-## version=1,
-## )
-## db.session.add(burn_list)
-## db.session.commit()
-##
- #generate dict
-## b = BurnList.query.all()
-## print(b)
-## burn_dict = {}
-## for i in b:
-## print(i.dmr_id)
-## burn_dict[i.dmr_id] = i.version
-## content = burn_dict
-## # delete
-#### delete_b = BurnList.query.filter_by(dmr_id=3153591).first()
-#### db.session.delete(delete_b)
-#### db.session.commit()
-## a = AuthLog.query.all()
-## print(a)
-## authlog_flush()
-## peer_delete('mmdvm', 1)
- user_ids = ast.literal_eval(u.dmr_ids)
- for i in user_ids.items():# active_tgs:
- print(active_tgs['test'][i[0]])
- content = active_tgs['test'][i[0]][1]['2']
-## content = user_ids
- return render_template('flask_user_layout.html', markup_content = Markup(content))
-
- def get_peer_configs(_server_name):
- mmdvm_pl = mmdvmPeer.query.filter_by(server=_server_name).filter_by(enabled=True).all()
- xlx_pl = xlxPeer.query.filter_by(server=_server_name).filter_by(enabled=True).all()
-## print(mmdvm_pl)
- peer_config_list = {}
- for i in mmdvm_pl:
-## print(i.master_ip)
- peer_config_list.update({i.name: {
- 'MODE': 'PEER',
- 'ENABLED': i.enabled,
- 'LOOSE': i.loose,
- 'SOCK_ADDR': (gethostbyname(i.ip), i.port),
- 'IP': i.ip,
- 'PORT': i.port,
- 'MASTER_SOCKADDR': (gethostbyname(i.master_ip), i.master_port),
- 'MASTER_IP': i.master_ip,
- 'MASTER_PORT': i.master_port,
-
- 'PASSPHRASE': i.passphrase,
- 'CALLSIGN': i.callsign,
- 'RADIO_ID': int(i.radio_id), #int(i.radio_id).to_bytes(4, 'big'),
- 'RX_FREQ': i.rx_freq,
- 'TX_FREQ': i.tx_freq,
- 'TX_POWER': i.tx_power,
- 'COLORCODE': i.color_code,
- 'LATITUDE': i.latitude,
- 'LONGITUDE': i.longitude,
- 'HEIGHT': i.height,
- 'LOCATION': i.location,
- 'DESCRIPTION': i.description,
- 'SLOTS': i.slots,
- 'URL': i.url,
- 'GROUP_HANGTIME': i.group_hangtime,
- 'OPTIONS': i.options,
- 'USE_ACL': i.use_acl,
- 'SUB_ACL': i.sub_acl,
- 'TG1_ACL': i.tg1_acl,
- 'TG2_ACL': i.tg2_acl
- }})
- for i in xlx_pl:
- peer_config_list.update({i.name: {
- 'MODE': 'XLXPEER',
- 'ENABLED': i.enabled,
- 'LOOSE': i.loose,
- 'SOCK_ADDR': (gethostbyname(i.ip), i.port),
- 'IP': i.ip,
- 'PORT': i.port,
- 'MASTER_SOCKADDR': (gethostbyname(i.master_ip), i.master_port),
- 'MASTER_IP': i.master_ip,
- 'MASTER_PORT': i.master_port,
-
- 'PASSPHRASE': i.passphrase,
- 'CALLSIGN': i.callsign,
- 'RADIO_ID': int(i.radio_id), #int(i.radio_id).to_bytes(4, 'big'),
- 'RX_FREQ': i.rx_freq,
- 'TX_FREQ': i.tx_freq,
- 'TX_POWER': i.tx_power,
- 'COLORCODE': i.color_code,
- 'LATITUDE': i.latitude,
- 'LONGITUDE': i.longitude,
- 'HEIGHT': i.height,
- 'LOCATION': i.location,
- 'DESCRIPTION': i.description,
- 'SLOTS': i.slots,
- 'URL': i.url,
- 'OPTIONS': i.options,
- 'GROUP_HANGTIME': i.group_hangtime,
- 'XLXMODULE': i.xlxmodule,
- 'USE_ACL': i.use_acl,
- 'SUB_ACL': i.sub_acl,
- 'TG1_ACL': i.tg1_acl,
- 'TG2_ACL': i.tg2_acl
- }})
-#### print('peers')
-## print('----------------')
- return peer_config_list
-
- def get_burnlist():
- b = BurnList.query.all()
- #print(b)
- burn_dict = {}
- for i in b:
- #print(i.dmr_id)
- burn_dict[i.dmr_id] = i.version
- return burn_dict
-
- def add_burnlist(_dmr_id, _version):
- burn_list = BurnList(
- dmr_id=_dmr_id,
- version=_version,
- )
- db.session.add(burn_list)
- db.session.commit()
-
- def update_burnlist(_dmr_id, _version):
- update_b = BurnList.query.filter_by(dmr_id=_dmr_id).first()
- update_b.version=_version
- db.session.commit()
- def delete_burnlist(_dmr_id):
- delete_b = BurnList.query.filter_by(dmr_id=_dmr_id).first()
- db.session.delete(delete_b)
- db.session.commit()
-
- def authlog_add(_dmr_id, _peer_ip, _server_name, _portal_username, _auth_method, _login_type):
- auth_log_add = AuthLog(
- login_dmr_id=_dmr_id,
- login_time=datetime.datetime.utcnow(),
- portal_username = _portal_username,
- peer_ip = _peer_ip,
- server_name = _server_name,
- login_auth_method=_auth_method,
- login_type=_login_type
- )
- db.session.add(auth_log_add)
- db.session.commit()
-
- def authlog_flush():
- AuthLog.query.delete()
- db.session.commit()
-
- def authlog_flush_user(_user):
- flush_e = AuthLog.query.filter_by(portal_username=_user).all()
- for i in flush_e:
- db.session.delete(i)
- db.session.commit()
-
- def authlog_flush_dmr_id(_dmr_id):
- flush_e = AuthLog.query.filter_by(login_dmr_id=_dmr_id).all()
- for i in flush_e:
- db.session.delete(i)
- db.session.commit()
- def authlog_flush_mmdvm_server(_mmdvm_serv):
- flush_e = AuthLog.query.filter_by(server_name=_mmdvm_serv).all()
- for i in flush_e:
- db.session.delete(i)
- db.session.commit()
- def authlog_flush_ip(_ip):
- flush_e = AuthLog.query.filter_by(peer_ip=_ip).all()
- for i in flush_e:
- db.session.delete(i)
- db.session.commit()
-## def peer_delete(_mode, _id):
-## if _mode == 'xlx':
-## p = xlxPeer.query.filter_by(id=_id).first()
-## if _mode == 'mmdvm':
-## p = mmdvmPeer.query.filter_by(id=_id).first()
-## db.session.delete(p)
-## db.session.commit()
-
- def server_delete(_name):
- s = ServerList.query.filter_by(name=_name).first()
- m = MasterList.query.filter_by(server=_name).all()
- p = ProxyList.query.filter_by(server=_name).all()
- o = OBP.query.filter_by(server=_name).all()
- dr = BridgeRules.query.filter_by(server=_name).all()
- mp = mmdvmPeer.query.filter_by(server=_name).all()
- xp = xlxPeer.query.filter_by(server=_name).all()
- for d in m:
- db.session.delete(d)
- for d in p:
- db.session.delete(d)
- for d in o:
- db.session.delete(d)
- for d in dr:
- db.session.delete(d)
- for d in mp:
- db.session.delete(d)
- for d in xp:
- db.session.delete(d)
- db.session.delete(s)
-
- db.session.commit()
- def peer_delete(_mode, _server, _name):
- if _mode == 'mmdvm':
- p = mmdvmPeer.query.filter_by(server=_server).filter_by(name=_name).first()
- if _mode == 'xlx':
- p = xlxPeer.query.filter_by(server=_server).filter_by(name=_name).first()
- dr = BridgeRules.query.filter_by(server=_server).filter_by(system_name=_name).all()
- for d in dr:
- db.session.delete(d)
- db.session.delete(p)
- db.session.commit()
-
- def shared_secrets():
- s = ServerList.query.all() #filter_by(name=_name).first()
- r_list = []
- for i in s:
- r_list.append(str(i.secret))
- return r_list
-
- def bridge_add(_name, _desc, _public, _tg):
- add_bridge = BridgeList(
- bridge_name = _name,
- description = _desc,
- public_list = _public,
- tg = _tg
- )
- db.session.add(add_bridge)
- db.session.commit()
- def update_bridge_list(_name, _desc, _public, _new_name, _tg):
- bl = BridgeList.query.filter_by(bridge_name=_name).first()
- bl.bridge_name = _new_name
- bl.description = _desc
- bl.public_list = _public
- bl.tg = _tg
- db.session.commit()
-
- def bridge_delete(_name): #, _server):
- bl = BridgeList.query.filter_by(bridge_name=_name).first()
- db.session.delete(bl)
- sl = ServerList.query.all()
- for i in sl:
- delete_system_bridge(_name, i.name)
- db.session.commit()
-
- def generate_rules(_name):
-
- # generate UNIT list
-## print('get rules')
-## print(_name)
- xlx_p = xlxPeer.query.filter_by(server=_name).all()
- mmdvm_p = mmdvmPeer.query.filter_by(server=_name).all()
- all_m = MasterList.query.filter_by(server=_name).all()
- all_o = OBP.query.filter_by(server=_name).all()
- all_p = ProxyList.query.filter_by(server=_name).all()
- rules = BridgeRules.query.filter_by(server=_name).all()
- UNIT = []
- BRIDGES = {}
- disabled = {}
- for i in all_m:
- if i.active == False:
- disabled[i.name] = i.name
- else:
- if i.enable_unit == True:
- UNIT.append(i.name)
- for i in all_p:
- if i.active == False:
- disabled[i.name] = i.name
- else:
- if i.enable_unit == True:
- n_systems = i.internal_stop_port - i.internal_start_port
- n_count = 0
- while n_count < n_systems:
- UNIT.append(i.name + '-' + str(n_count))
- n_count = n_count + 1
- for i in all_o:
- if i.enabled == False:
- disabled[i.name] = i.name
- else:
- if i.enable_unit == True:
- UNIT.append(i.name)
- for i in xlx_p:
- if i.enabled == False:
- disabled[i.name] = i.name
- else:
- if i.enable_unit == True:
- UNIT.append(i.name)
- for i in mmdvm_p:
- if i.enabled == False:
- disabled[i.name] = i.name
- else:
- if i.enable_unit == True:
- UNIT.append(i.name)
- temp_dict = {}
- # populate dict with needed bridges
- for r in rules:
-## print(r.bridge_name)
-## b = BridgeRules.query.filter_by(server=_name).filter_by(server=_name).all()
-## for d in temp_dict.items():
-## if r.bridge_name == d[0]:
-## print('update rule')
-## if r.bridge_name != d[0]:
-## print('add dict entry and rule')
- temp_dict[r.bridge_name] = []
-## print(temp_dict)
- BRIDGES = temp_dict.copy()
- for r in temp_dict.items():
- b = BridgeRules.query.filter_by(bridge_name=r[0]).filter_by(server=_name).all()
- for s in b:
- try:
- if s.system_name == disabled[s.system_name]:
- pass
- except:
- if s.timeout == '':
- timeout = 0
- else:
- timeout = int(s.timeout)
- if s.proxy == True:
- p = ProxyList.query.filter_by(server=_name).filter_by(name=s.system_name).first()
- print(p.external_port)
- n_systems = p.internal_stop_port - p.internal_start_port
- n_count = 0
- while n_count < n_systems:
- BRIDGES[r[0]].append({'SYSTEM': s.system_name + '-' + str(n_count), 'TS': s.ts, 'TGID': s.tg, 'ACTIVE': s.active, 'TIMEOUT': timeout, 'TO_TYPE': s.to_type, 'ON': ast.literal_eval(str('[' + s.on + ']')), 'OFF': ast.literal_eval(str('[4000,' + s.off + ']')), 'RESET': ast.literal_eval(str('[' + s.reset + ']'))})
- n_count = n_count + 1
-
- else:
- BRIDGES[r[0]].append({'SYSTEM': s.system_name, 'TS': s.ts, 'TGID': s.tg, 'ACTIVE': s.active, 'TIMEOUT': timeout, 'TO_TYPE': s.to_type, 'ON': ast.literal_eval(str('[' + s.on + ']')), 'OFF': ast.literal_eval(str('[' + s.off + ']')), 'RESET': ast.literal_eval(str('[' + s.reset + ']'))})
-
-## for d in b:
-## print(b.system_name)
-
-## if r.bridge_name == d[0]:
-## print('update rule')
-## if r.bridge_name != d[0]:
-## print('add dict entry and rule')
-
-## print(r.tg)
-## print(BRIDGES)
- return [UNIT, BRIDGES]
-
-
- def server_get(_name):
-## print(_name)
- #s = ServerList.query.filter_by(name=_name).first()
- # print(s.name)
- i = ServerList.query.filter_by(name=_name).first()
-## print(i.name)
- s_config = {}
- s_config['GLOBAL'] = {}
- s_config['REPORTS'] = {}
- s_config['ALIASES'] = {}
- s_config['USER_MANAGER'] = {}
-
- s_config['GLOBAL'].update({
- 'PATH': i.global_path,
- 'PING_TIME': i.global_ping_time,
- 'MAX_MISSED': i.global_max_missed,
- 'USE_ACL': i.global_use_acl,
- 'REG_ACL': i.global_reg_acl,
- 'SUB_ACL': i.global_sub_acl,
- 'TG1_ACL': i.global_tg1_acl,
- 'TG2_ACL': i.global_tg2_acl
- })
-
- s_config['REPORTS'].update({
- 'REPORT': i.report_enable,
- 'REPORT_INTERVAL': i.report_interval,
- 'REPORT_PORT': i.report_port,
- 'REPORT_CLIENTS': i.report_clients.split(',')
- })
- s_config['ALIASES'].update({
- 'TRY_DOWNLOAD':i.ai_try_download,
- 'PATH': i.ai_path,
- 'PEER_FILE': i.ai_peer_file,
- 'SUBSCRIBER_FILE': i.ai_subscriber_file,
- 'TGID_FILE': i.ai_tgid_file,
- 'PEER_URL': i.ai_peer_url,
- 'SUBSCRIBER_URL': i.ai_subs_url,
- 'STALE_TIME': i.ai_stale * 86400,
- })
- s_config['USER_MANAGER'].update({
- 'SHORTEN_LENGTH': shorten_length,
- 'SHORTEN_SAMPLE': shorten_sample,
- 'EXTRA_1': extra_1,
- 'EXTRA_2': extra_2,
- 'EXTRA_INT_1': extra_int_1,
- 'EXTRA_INT_2': extra_int_2,
- 'APPEND_INT': append_int,
- 'SHORTEN_PASSPHRASE': i.um_shorten_passphrase,
- 'BURN_FILE': i.um_burn_file,
- 'BURN_INT': burn_int,
-
-
- })
- print(s_config['REPORTS'])
- return s_config
- def masters_get(_name):
-## # print(_name)
- #s = ServerList.query.filter_by(name=_name).first()
- # print(s.name)
- i = MasterList.query.filter_by(server=_name).filter_by(active=True).all()
- o = OBP.query.filter_by(server=_name).filter_by(enabled=True).all()
- p = ProxyList.query.filter_by(server=_name).filter_by(active=True).all()
- # print('get masters')
- master_config_list = {}
-## master_config_list['SYSTEMS'] = {}
- # print(i)
- for m in i:
- print (m.name)
- master_config_list.update({m.name: {
- 'MODE': 'MASTER',
- 'ENABLED': m.active,
- 'USE_USER_MAN': m.enable_um,
- 'STATIC_APRS_POSITION_ENABLED': m.static_positions,
- 'REPEAT': m.repeat,
- 'MAX_PEERS': m.max_peers,
- 'IP': m.ip,
- 'PORT': m.port,
- 'PASSPHRASE': m.passphrase, #bytes(m.passphrase, 'utf-8'),
- 'GROUP_HANGTIME': m.group_hang_time,
- 'USE_ACL': m.use_acl,
- 'REG_ACL': m.reg_acl,
- 'SUB_ACL': m.sub_acl,
- 'TG1_ACL': m.tg1_acl,
- 'TG2_ACL': m.tg2_acl
- }})
- master_config_list[m.name].update({'PEERS': {}})
- for obp in o:
-## print(type(obp.network_id))
- master_config_list.update({obp.name: {
- 'MODE': 'OPENBRIDGE',
- 'ENABLED': obp.enabled,
- 'NETWORK_ID': obp.network_id, #int(obp.network_id).to_bytes(4, 'big'),
- 'IP': gethostbyname(obp.ip),
- 'PORT': obp.port,
- 'PASSPHRASE': obp.passphrase, #bytes(obp.passphrase.ljust(20,'\x00')[:20], 'utf-8'),
- 'TARGET_SOCK': (obp.target_ip, obp.target_port),
- 'TARGET_IP': gethostbyname(obp.target_ip),
- 'TARGET_PORT': obp.target_port,
- 'BOTH_SLOTS': obp.both_slots,
- 'USE_ACL': obp.use_acl,
- 'SUB_ACL': obp.sub_acl,
- 'TG1_ACL': obp.tg_acl,
- 'TG2_ACL': 'PERMIT:ALL'
- }})
- for pr in p:
- master_config_list.update({pr.name: {
- 'MODE': 'PROXY',
- 'ENABLED': pr.active,
- 'EXTERNAL_PROXY_SCRIPT': pr.external_proxy,
- 'STATIC_APRS_POSITION_ENABLED': pr.static_positions,
- 'USE_USER_MAN': pr.enable_um,
- 'REPEAT': pr.repeat,
- 'PASSPHRASE': pr.passphrase, #bytes(pr.passphrase, 'utf-8'),
- 'EXTERNAL_PORT': pr.external_port,
- 'INTERNAL_PORT_START': pr.internal_start_port,
- 'INTERNAL_PORT_STOP': pr.internal_stop_port,
- 'GROUP_HANGTIME': pr.group_hang_time,
- 'USE_ACL': pr.use_acl,
- 'REG_ACL': pr.reg_acl,
- 'SUB_ACL': pr.sub_acl,
- 'TG1_ACL': pr.tg1_acl,
- 'TG2_ACL': pr.tg2_acl
- }})
- master_config_list[pr.name].update({'PEERS': {}})
-
- # print(master_config_list)
- return master_config_list
-
- def add_system_rule(_bridge_name, _system_name, _ts, _tg, _active, _timeout, _to_type, _on, _off, _reset, _server, _public_list):
- proxy = ProxyList.query.filter_by(server=_server).filter_by(name=_system_name).first()
- is_proxy = False
- try:
- if _system_name == proxy.name:
- is_proxy = True
- except:
- pass
- add_system = BridgeRules(
- bridge_name = _bridge_name,
- system_name = _system_name,
- ts = _ts,
- tg = _tg,
- active = _active,
- timeout = _timeout,
- to_type = _to_type,
- on = _on,
- off = _off,
- reset = _reset,
- server = _server,
- public_list = _public_list,
- proxy = is_proxy
- )
- db.session.add(add_system)
- db.session.commit()
-
- def delete_system_bridge(_name, _server):
- dr = BridgeRules.query.filter_by(server=_server).filter_by(bridge_name=_name).all()
- for i in dr:
- db.session.delete(i)
- db.session.commit()
-
- def delete_system_rule(_name, _server, _system):
- dr = BridgeRules.query.filter_by(server=_server).filter_by(bridge_name=_name).filter_by(system_name=_system).first()
- db.session.delete(dr)
- db.session.commit()
-
-
- def server_edit(_name, _secret, _ip, _public_list, _port, _global_path, _global_ping_time, _global_max_missed, _global_use_acl, _global_reg_acl, _global_sub_acl, _global_tg1_acl, _global_tg2_acl, _ai_subscriber_file, _ai_try_download, _ai_path, _ai_peer_file, _ai_tgid_file, _ai_peer_url, _ai_subs_url, _ai_stale, _um_shorten_passphrase, _um_burn_file, _report_enable, _report_interval, _report_port, _report_clients, _unit_time, _notes):
- s = ServerList.query.filter_by(name=_name).first()
- # print(_name)
- if _secret == '':
- s.secret = s.secret
- else:
- s.secret = hashlib.sha256(_secret.encode()).hexdigest()
- s.public_list = _public_list
- s.ip = _ip
- s.port = _port
- s.global_path =_global_path
- s.global_ping_time = _global_ping_time
- s.global_max_missed = _global_max_missed
- s.global_use_acl = _global_use_acl
- s.global_reg_acl = _global_reg_acl
- s.global_sub_acl = _global_sub_acl
- s.global_tg1_acl = _global_tg1_acl
- s.global_tg2_acl = _global_tg2_acl
- s.ai_try_download = _ai_try_download
- s.ai_path = _ai_path
- s.ai_peer_file = _ai_peer_file
- s.ai_subscriber_file = _ai_subscriber_file
- s.ai_tgid_file = _ai_tgid_file
- s.ai_peer_url = _ai_peer_url
- s.ai_subs_url = _ai_subs_url
- s.ai_stale = _ai_stale
- # Pull from config file for now
-## um_append_int = db.Column(db.Integer(), primary_key=False, server_default='2')
- s.um_shorten_passphrase = _um_shorten_passphrase
- s.um_burn_file = _um_burn_file
- # Pull from config file for now
-## um_burn_int = db.Column(db.Integer(), primary_key=False, server_default='6')
- s.report_enable = _report_enable
- s.report_interval = _report_interval
- s.report_port = _report_port
- s.report_clients = _report_clients
- s.unit_time = int(_unit_time)
- s.notes = _notes
- db.session.commit()
-
- def master_delete(_mode, _server, _name):
- if _mode == 'MASTER':
- m = MasterList.query.filter_by(server=_server).filter_by(name=_name).first()
- if _mode == 'PROXY':
- m = ProxyList.query.filter_by(server=_server).filter_by(name=_name).first()
- if _mode == 'OBP':
- m = OBP.query.filter_by(server=_server).filter_by(name=_name).first()
- dr = BridgeRules.query.filter_by(server=_server).filter_by(system_name=_name).all()
- for d in dr:
- db.session.delete(d)
- db.session.delete(m)
- db.session.commit()
-
- def edit_master(_mode, _name, _server, _static_positions, _repeat, _active, _max_peers, _ip, _port, _enable_um, _passphrase, _group_hang_time, _use_acl, _reg_acl, _sub_acl, _tg1_acl, _tg2_acl, _enable_unit, _notes, _external_proxy, _int_start_port, _int_stop_port, _network_id, _target_ip, _target_port, _both_slots, _public):
-## print(_mode)
-#### print(_server)
-## print(_name)
- if _mode == 'MASTER':
-## print(_name)
- m = MasterList.query.filter_by(server=_server).filter_by(name=_name).first()
-## m.name = _name,
- m.static_positions = _static_positions
- m.repeat = _repeat
- m.active = _active
- m.max_peers = int(_max_peers)
- m.ip = _ip
- m.port = int(_port)
- m.enable_um = _enable_um
- m.passphrase = str(_passphrase)
- m.group_hang_time = int(_group_hang_time)
- m.use_acl = _use_acl
- m.reg_acl = _reg_acl
- m.sub_acl = _sub_acl
- m.tg1_acl = _tg1_acl
- m.tg2_acl = _tg2_acl
- m.enable_unit = _enable_unit
-## m.server = _server
- m.notes = _notes
- m.public_list = _public
- db.session.commit()
- if _mode == 'OBP':
- # print(_enable_unit)
-## print(enable_unit)
- o = OBP.query.filter_by(server=_server).filter_by(name=_name).first()
- o.enabled = _active
- o.network_id = _network_id
- o.ip = _ip
- o.port = _port
- o.passphrase = _passphrase
- o.target_ip = _target_ip
- o.target_port = _target_port
- o.both_slots = _both_slots
- o.use_acl = _use_acl
- o.sub_acl = _sub_acl
- o.tg1_acl = _tg1_acl
- o.tg2_acl = _tg2_acl
- o.enable_unit = _enable_unit
- o.notes = _notes
- db.session.commit()
- if _mode == 'PROXY':
-## print(_int_start_port)
-## print(_int_stop_port)
- p = ProxyList.query.filter_by(server=_server).filter_by(name=_name).first()
- p.name = _name
- p.static_positions = _static_positions
- p.repeat = _repeat
- p.active = _active
- p.enable_um = _enable_um
- p.passphrase = _passphrase
- p.external_proxy = _external_proxy
- external_port = int(_port)
- p.group_hang_time = int(_group_hang_time)
- p.internal_start_port = _int_start_port
- p.internal_stop_port = _int_stop_port
- p.use_acl = _use_acl
- p.reg_acl = _reg_acl
- p.sub_acl = _sub_acl
- p.tg1_acl = _tg1_acl
- p.tg2_acl = _tg2_acl
- p.enable_unit = _enable_unit
- p.server = _server
- p.notes = _notes
- p.public_list = _public
- db.session.commit()
-## add_proxy = ProxyList(
-## name = _name,
-## static_positions = _static_positions,
-## repeat = _repeat,
-## active = _active,
-## enable_um = _enable_um,
-## passphrase = _passphrase,
-## external_proxy = _external_proxy,
-## group_hang_time = int(_group_hang_time),
-## internal_start_port = int(_int_start_port),
-## internal_stop_port = int(_int_stop_port),
-## use_acl = _use_acl,
-## reg_acl = _reg_acl,
-## sub_acl = _sub_acl,
-## tg1_acl = _tg1_acl,
-## tg2_acl = _tg2_acl,
-## enable_unit = _enable_unit,
-## server = _server,
-## notes = _notes
-## )
-## db.session.add(add_master)
-
- def add_master(_mode, _name, _server, _static_positions, _repeat, _active, _max_peers, _ip, _port, _enable_um, _passphrase, _group_hang_time, _use_acl, _reg_acl, _sub_acl, _tg1_acl, _tg2_acl, _enable_unit, _notes, _external_proxy, _int_start_port, _int_stop_port, _network_id, _target_ip, _target_port, _both_slots, _public):
- # print(_mode)
- if _mode == 'MASTER':
- add_master = MasterList(
- name = _name,
- static_positions = _static_positions,
- repeat = _repeat,
- active = _active,
- max_peers = int(_max_peers),
- ip = _ip,
- port = int(_port),
- enable_um = _enable_um,
- passphrase = _passphrase,
- group_hang_time = int(_group_hang_time),
- use_acl = _use_acl,
- reg_acl = _reg_acl,
- sub_acl = _sub_acl,
- tg1_acl = _tg1_acl,
- tg2_acl = _tg2_acl,
- enable_unit = _enable_unit,
- server = _server,
- notes = _notes,
- public_list = _public
- )
- db.session.add(add_master)
- db.session.commit()
- if _mode == 'PROXY':
- add_proxy = ProxyList(
- name = _name,
- static_positions = _static_positions,
- repeat = _repeat,
- active = _active,
- enable_um = _enable_um,
- passphrase = _passphrase,
- external_proxy = _external_proxy,
- external_port = int(_port),
- group_hang_time = int(_group_hang_time),
- internal_start_port = int(_int_start_port),
- internal_stop_port = int(_int_stop_port),
- use_acl = _use_acl,
- reg_acl = _reg_acl,
- sub_acl = _sub_acl,
- tg1_acl = _tg1_acl,
- tg2_acl = _tg2_acl,
- enable_unit = _enable_unit,
- server = _server,
- notes = _notes,
- public_list = _public
- )
- db.session.add(add_proxy)
- db.session.commit()
- if _mode == 'OBP':
- # print(_name)
- # print(_network_id)
- add_OBP = OBP(
- name = _name,
- enabled = _active,
- network_id = _network_id, #
- ip = _ip,
- port = _port,
- passphrase = _passphrase,
- target_ip = _target_ip,#
- target_port = _target_port,#
- both_slots = _both_slots,#
- use_acl = _use_acl,
- sub_acl = _sub_acl,
- tg_acl = _tg1_acl,
- enable_unit = _enable_unit,
- server = _server,
- notes = _notes,
- )
- db.session.add(add_OBP)
- db.session.commit()
-
-
- def server_add(_name, _secret, _ip, _port, _global_path, _global_ping_time, _global_max_missed, _global_use_acl, _global_reg_acl, _global_sub_acl, _global_tg1_acl, _global_tg2_acl, _ai_subscriber_file, _ai_try_download, _ai_path, _ai_peer_file, _ai_tgid_file, _ai_peer_url, _ai_subs_url, _ai_stale, _um_shorten_passphrase, _um_burn_file, _report_enable, _report_interval, _report_port, _report_clients, _unit_time, _notes):
- add_server = ServerList(
- name = _name,
- secret = hashlib.sha256(_secret.encode()).hexdigest(),
-## public_list = _public_list,
- ip = _ip,
- port = _port,
- global_path =_global_path,
- global_ping_time = _global_ping_time,
- global_max_missed = _global_max_missed,
- global_use_acl = _global_use_acl,
- global_reg_acl = _global_reg_acl,
- global_sub_acl = _global_sub_acl,
- global_tg1_acl = _global_tg1_acl,
- global_tg2_acl = _global_tg2_acl,
- ai_try_download = _ai_try_download,
- ai_path = _ai_path,
- ai_peer_file = _ai_peer_file,
- ai_subscriber_file = _ai_subscriber_file,
- ai_tgid_file = _ai_tgid_file,
- ai_peer_url = _ai_peer_url,
- ai_subs_url = _ai_subs_url,
- ai_stale = _ai_stale,
- # Pull from config file for now
-## um_append_int = db.Column(db.Integer(), primary_key=False, server_default='2')
- um_shorten_passphrase = _um_shorten_passphrase,
- um_burn_file = _um_burn_file,
- # Pull from config file for now
-## um_burn_int = db.Column(db.Integer(), primary_key=False, server_default='6')
- report_enable = _report_enable,
- report_interval = _report_interval,
- report_port = _report_port,
- report_clients = _report_clients,
- unit_time = int(_unit_time),
- notes = _notes
- )
- db.session.add(add_server)
- db.session.commit()
- def peer_add(_mode, _name, _enabled, _loose, _ip, _port, _master_ip, _master_port, _passphrase, _callsign, _radio_id, _rx, _tx, _tx_power, _cc, _lat, _lon, _height, _loc, _desc, _slots, _url, _grp_hang, _xlx_mod, _opt, _use_acl, _sub_acl, _1_acl, _2_acl, _svr, _enable_unit, _notes):
- if _mode == 'xlx':
- xlx_peer_add = xlxPeer(
- name = _name,
- enabled = _enabled,
- loose = _loose,
- ip = _ip,
- port = _port,
- master_ip = _master_ip,
- master_port = _master_port,
- passphrase = _passphrase,
- callsign = _callsign,
- radio_id = _radio_id,
- rx_freq = _rx,
- tx_freq = _tx,
- tx_power = _tx_power,
- color_code = _cc,
- latitude = _lat,
- longitude = _lon,
- height = _height,
- location = _loc,
- description = _desc,
- slots = _slots,
- xlxmodule = _xlx_mod,
- url = _url,
- enable_unit = _enable_unit,
- group_hangtime = _grp_hang,
- use_acl = _use_acl,
- sub_acl = _sub_acl,
- tg1_acl = _1_acl,
- tg2_acl = _2_acl,
- server = _svr,
- notes = _notes
- )
- db.session.add(xlx_peer_add)
- db.session.commit()
- if _mode == 'mmdvm':
- mmdvm_peer_add = mmdvmPeer(
- name = _name,
- enabled = _enabled,
- loose = _loose,
- ip = _ip,
- port = _port,
- master_ip = _master_ip,
- master_port = _master_port,
- passphrase = _passphrase,
- callsign = _callsign,
- radio_id = _radio_id,
- rx_freq = _rx,
- tx_freq = _tx,
- tx_power = _tx_power,
- color_code = _cc,
- latitude = _lat,
- longitude = _lon,
- height = _height,
- location = _loc,
- description = _desc,
- slots = _slots,
- url = _url,
- enable_unit = _enable_unit,
- group_hangtime = _grp_hang,
- use_acl = _use_acl,
- sub_acl = _sub_acl,
- tg1_acl = _1_acl,
- tg2_acl = _2_acl,
- server = _svr,
- notes = _notes
- )
- db.session.add(mmdvm_peer_add)
- db.session.commit()
- def peer_edit(_mode, _server, _name, _enabled, _loose, _ip, _port, _master_ip, _master_port, _passphrase, _callsign, _radio_id, _rx, _tx, _tx_power, _cc, _lat, _lon, _height, _loc, _desc, _slots, _url, _grp_hang, _xlx_mod, _opt, _use_acl, _sub_acl, _1_acl, _2_acl, _enable_unit, _notes):
-## print(_mode)
- if _mode == 'mmdvm':
-## print(_server)
-## print(_name)
-## print(_name)
-## s = mmdvmPeer.query.filter_by(server=_server).filter_by(name=_name).first()
- p = mmdvmPeer.query.filter_by(server=_server).filter_by(name=_name).first()
- p.enabled = _enabled
- p.loose = _loose
- p.ip = _ip
- p.port = _port
- p.master_ip = _master_ip
- p.master_port = _master_port
- p.passphrase = _passphrase
- p.callsign = _callsign
- p.radio_id = _radio_id
- p.rx_freq = _rx
- p.tx_freq = _tx
- p.tx_power = _tx_power
- p.color_code = _cc
- p.latitude = _lat
- p.longitude = _lon
- p.height = _height
- p.location = _loc
- p.description = _desc
- p.slots = _slots
- p.url = _url
- p.enable_unit = _enable_unit
- p.group_hangtime = _grp_hang
- p.options = _opt
- p.use_acl = _use_acl
- p.sub_acl = _sub_acl
- p.tg1_acl = _1_acl
- p.tg2_acl = _2_acl
- p.notes = _notes
- if _mode == 'xlx':
-## print(type(_server))
-## print(type(_name))
-## print(type(_enabled))
-## print((_enable_unit))
-## print(type(_use_acl))
-#### print(_port)
-
-
-## s = mmdvmPeer.query.filter_by(server=_server).filter_by(name=_name).first()
- p = xlxPeer.query.filter_by(server=_server).filter_by(name=_name).first()
- # print(type(p.enable_unit))
- p.enabled = _enabled
- p.loose = _loose
- p.ip = _ip
- p.port = _port
- p.master_ip = _master_ip
- p.master_port = _master_port
- p.passphrase = _passphrase
- p.callsign = _callsign
- p.radio_id = _radio_id
- p.rx_freq = _rx
- p.tx_freq = _tx
- p.tx_power = _tx_power
- p.color_code = _cc
- p.latitude = _lat
- p.longitude = _lon
- p.height = _height
- p.location = _loc
- p.description = _desc
- p.slots = _slots
- p.url = _url
- p.options = _opt
- p.enable_unit = _enable_unit
- p.xlxmodule = _xlx_mod
- p.group_hangtime = _grp_hang
- p.use_acl = _use_acl
- p.sub_acl = _sub_acl
- p.tg1_acl = _1_acl
- p.tg2_acl = _2_acl
- p.notes = _notes
- db.session.commit()
-
-
-
-
-# Test server configs
-
- @app.route('/manage_servers', methods=['POST', 'GET'])
- @login_required
- @roles_required('Admin')
- def edit_server_db():
- # Edit server
- if request.args.get('save_mode'):# == 'new' and request.form.get('server_name'):
- _port = int(request.form.get('server_port'))
- _global_ping_time = int(request.form.get('ping_time'))
- _global_max_missed = int(request.form.get('max_missed'))
- _ai_stale = int(request.form.get('stale_days'))
- _report_interval = int(request.form.get('report_interval'))
- _report_port = int(request.form.get('report_port'))
- if request.form.get('use_acl') == 'True':
- _global_use_acl = True
- if request.form.get('aliases_enabled') == 'True':
- _ai_try_download = True
- if request.form.get('um_shorten_passphrase') == 'True':
- _um_shorten_passphrase = True
- if request.form.get('report') == 'True':
- _report_enabled = True
-## if request.form.get('public_list') == 'True':
-## public_list = True
- else:
- _global_use_acl = False
- _ai_try_download = False
- _um_shorten_passphrase = False
- _report_enabled = False
-## public_list = False
-
- if request.args.get('save_mode') == 'new':
- if request.form.get('server_name') == '':
- content = '''Server can't have blank name.
-Server saved.
- Server changed.
-Server deleted.
-
-''' - # Add new server - elif request.args.get('add'): # == 'yes': - content = ''' - -
-''' - else: - all_s = ServerList.query.all() - p_list = ''' -
| Add Server Config | -
- -
Name |
-Notes |
-
-'''
- for s in all_s:
- p_list = p_list + '''
-
| ''' + str(s.name) + ''' | -''' + s.notes + ''' | -
Redirecting in 3 seconds.
-''' - else: - if request.args.get('save_mode') == 'mmdvm_peer': - peer_add('mmdvm', request.form.get('name_text'), peer_enabled, peer_loose, request.form.get('ip'), request.form.get('port'), request.form.get('master_ip'), request.form.get('master_port'), request.form.get('passphrase'), request.form.get('callsign'), request.form.get('radio_id'), request.form.get('rx'), request.form.get('tx'), request.form.get('tx_power'), request.form.get('cc'), request.form.get('lat'), request.form.get('lon'), request.form.get('height'), request.form.get('location'), request.form.get('description'), request.form.get('slots'), request.form.get('url'), request.form.get('group_hangtime'), 'MMDVM', request.form.get('options'), use_acl, request.form.get('sub_acl'), request.form.get('tgid_ts1_acl'), request.form.get('tgid_ts2_acl'), request.form.get('server'), unit_enabled, request.form.get('notes')) - content = '''Redirecting in 3 seconds.
- ''' - if request.args.get('save_mode') == 'xlx_peer': - peer_add('xlx', request.form.get('name_text'), peer_enabled, peer_loose, request.form.get('ip'), request.form.get('port'), request.form.get('master_ip'), request.form.get('master_port'), request.form.get('passphrase'), request.form.get('callsign'), request.form.get('radio_id'), request.form.get('rx'), request.form.get('tx'), request.form.get('tx_power'), request.form.get('cc'), request.form.get('lat'), request.form.get('lon'), request.form.get('height'), request.form.get('location'), request.form.get('description'), request.form.get('slots'), request.form.get('url'), request.form.get('group_hangtime'), request.form.get('xlxmodule'), request.form.get('options'), use_acl, request.form.get('sub_acl'), request.form.get('tgid_ts1_acl'), request.form.get('tgid_ts2_acl'), request.form.get('server'), unit_enabled, request.form.get('notes')) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('add') == 'mmdvm' or request.args.get('add') == 'xlx': - s = ServerList.query.all() - if request.args.get('add') == 'mmdvm': - mode = 'MMDVM' - submit_link = 'manage_peers?save_mode=mmdvm_peer' - xlx_module = '' - if request.args.get('add') == 'xlx': - xlx_module = ''' --
Redirecting in 3 seconds.
-''' - elif request.args.get('edit_mmdvm') == 'save' or request.args.get('edit_xlx') == 'save': - peer_enabled = False - use_acl = False - peer_loose = True - unit_enabled = False - if request.form.get('enabled') == 'true': - peer_enabled = True -## if request.form.get('loose') == 'true': -## peer_loose = True - if request.form.get('use_acl') == 'True': - use_acl = True - if request.form.get('enable_unit') == 'True': - unit_enabled = True -## else: -## peer_loose = False -## print((unit_enabled)) -## print(type(peer_enabled)) -## print(type(use_acl)) - if request.args.get('edit_mmdvm') == 'save': - peer_edit('mmdvm', request.args.get('server'), request.args.get('name'), peer_enabled, peer_loose, request.form.get('ip'), request.form.get('port'), request.form.get('master_ip'), request.form.get('master_port'), request.form.get('passphrase'), request.form.get('callsign'), request.form.get('radio_id'), request.form.get('rx'), request.form.get('tx'), request.form.get('tx_power'), request.form.get('cc'), request.form.get('lat'), request.form.get('lon'), request.form.get('height'), request.form.get('location'), request.form.get('description'), request.form.get('slots'), request.form.get('url'), request.form.get('group_hangtime'), 'MMDVM', request.form.get('options'), use_acl, request.form.get('sub_acl'), request.form.get('tgid_ts1_acl'), request.form.get('tgid_ts2_acl'), unit_enabled, request.form.get('notes')) - content = '''Redirecting in 3 seconds.
-''' - if request.args.get('edit_xlx') == 'save': - peer_edit('xlx', request.args.get('server'), request.args.get('name'), peer_enabled, peer_loose, request.form.get('ip'), request.form.get('port'), request.form.get('master_ip'), request.form.get('master_port'), request.form.get('passphrase'), request.form.get('callsign'), request.form.get('radio_id'), request.form.get('rx'), request.form.get('tx'), request.form.get('tx_power'), request.form.get('cc'), request.form.get('lat'), request.form.get('lon'), request.form.get('height'), request.form.get('location'), request.form.get('description'), request.form.get('slots'), request.form.get('url'), request.form.get('group_hangtime'), request.form.get('xlxmodule'), request.form.get('options'), use_acl, request.form.get('sub_acl'), request.form.get('tgid_ts1_acl'), request.form.get('tgid_ts2_acl'), unit_enabled, request.form.get('notes')) - content = '''Redirecting in 3 seconds.
-''' - elif request.args.get('server') and request.args.get('peer_name') and request.args.get('mode'): # and request.args.get('edit_peer') and request.args.get('mode') == 'mmdvm': - if request.args.get('mode') == 'mmdvm': - p = mmdvmPeer.query.filter_by(server=request.args.get('server')).filter_by(name=request.args.get('peer_name')).first() - xlx_module = '' - mode = "MMDVM" - form_submit = ''' - --''' - else: - all_s = ServerList.query.all() - p_list = '' - for s in all_s: - # print(s.name) - p_list = p_list + ''' -
| Name | -Mode | -Notes | - -
| ''' + str(p.name) + ''' | -MMDVM | -''' + p.notes + ''' | - -
| ''' + str(x.name) + ''' | -XLX | -''' + x.notes + ''' | - -
| Add MMDVM peer | -Add XLX peer | -
- -''' + p_list - - return render_template('flask_user_layout.html', markup_content = Markup(content)) - - - @app.route('/manage_masters', methods=['POST', 'GET']) - @login_required - @roles_required('Admin') - def manage_masters(): - #PROXY - if request.args.get('proxy_save'): - active = False - use_acl = False - enable_unit = False - repeat = True - aprs_pos = False - enable_um = True - external_proxy = False - public = False - if request.form.get('enable_um') == 'False': - enable_um = False - if request.form.get('aprs_pos') == 'True': - aprs_pos = True - if request.form.get('enabled') == 'True': - active = True - if request.form.get('use_acl') == 'True': - use_acl = True - if request.form.get('enable_unit') == 'True': - enable_unit = True - if request.form.get('repeat') == 'False': - repeat = False - if request.form.get('external_proxy') == 'True': - external_proxy = True - if request.form.get('public_list') == 'True': - public = True - if request.args.get('proxy_save') == 'add': - if request.form.get('name_text') == '': - content = '''
Redirecting in 3 seconds.
-''' - else: - add_master('PROXY', request.form.get('name_text'), request.form.get('server'), aprs_pos, repeat, active, 0, request.form.get('ip'), request.form.get('external_port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), external_proxy, request.form.get('int_port_start'), request.form.get('int_port_stop'), '', '', '', '', public) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('proxy_save') == 'edit': -## print(request.args.get('name')) - edit_master('PROXY', request.args.get('name'), request.args.get('server'), aprs_pos, repeat, active, 0, request.form.get('ip'), request.form.get('external_port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), external_proxy, request.form.get('int_port_start'), request.form.get('int_port_stop'), '', '', '', '', public) - content = '''Redirecting in 3 seconds.
-''' - elif request.args.get('proxy_save') == 'delete': - master_delete('PROXY', request.args.get('server'), request.args.get('name')) - content = '''Redirecting in 3 seconds.
-''' - # OBP - elif request.args.get('OBP_save'): - enabled = False - use_acl = False - enable_unit = False - both_slots = True - if request.form.get('enabled') == 'True': - enabled = True - if request.form.get('use_acl') == 'True': - use_acl = True - if request.form.get('enable_unit') == 'True': - enable_unit = True - if request.form.get('both_slots') == 'False': - both_slots = False - if request.args.get('OBP_save') == 'add': - if request.form.get('name_text') == '': - content = '''Redirecting in 3 seconds.
-''' - else: - add_master('OBP', request.form.get('name_text'), request.form.get('server'), '', '', enabled, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), '', request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('tg_acl'), '', enable_unit, request.form.get('notes'), '', '', '', request.form.get('network_id'), request.form.get('target_ip'), request.form.get('target_port'), both_slots, '') - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('OBP_save') == 'edit': - edit_master('OBP', request.args.get('name'), request.args.get('server'), '', '', enabled, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), '', request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('tg_acl'), '', enable_unit, request.form.get('notes'), '', '', '', request.form.get('network_id'), request.form.get('target_ip'), request.form.get('target_port'), both_slots, '') - content = '''Redirecting in 3 seconds.
-''' - elif request.args.get('OBP_save') == 'delete': - master_delete('OBP', request.args.get('server'), request.args.get('name')) - content = '''Redirecting in 3 seconds.
-''' - # MASTER - elif request.args.get('master_save'): - aprs_pos = False - repeat = False - active = False - use_acl = False - enable_um = False - enable_unit = False - public = False - if request.form.get('aprs_pos') == 'True': - aprs_pos = True - if request.form.get('repeat') == 'True': - repeat = True - if request.form.get('enabled') == 'True': - active = True - if request.form.get('use_acl') == 'True': - use_acl = True - if request.form.get('enable_um') == 'True': - enable_um = True - if request.form.get('enable_unit') == 'True': - enable_unit = True - if request.form.get('public_list') == 'True': - public = True - if request.args.get('master_save') == 'add': - if request.form.get('name_text') == '': - content = '''Redirecting in 3 seconds.
-''' - else: - add_master('MASTER', request.form.get('name_text'), request.form.get('server'), aprs_pos, repeat, active, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), '', '', '', '', '', '', '', public) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('master_save') == 'edit': - edit_master('MASTER', request.args.get('name'), request.args.get('server'), aprs_pos, repeat, active, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), '', '', '', '', '', '', '', public) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('master_save') == 'delete': - master_delete('MASTER', request.args.get('server'), request.args.get('name')) - content = '''Redirecting in 3 seconds.
-''' - elif request.args.get('add_OBP'): - s = ServerList.query.all() - server_options = '' - for i in s: - server_options = server_options + '''\n''' - content = ''' -- -
- - -
- -''' - elif request.args.get('edit_proxy'): - # print(request.args.get('server')) - # print(request.args.get('edit_proxy')) - p = ProxyList.query.filter_by(server=request.args.get('server')).filter_by(name=request.args.get('edit_proxy')).first() - content = ''' -
- -
-''' - - elif request.args.get('add_proxy'): - s = ServerList.query.all() - server_options = '' - for i in s: - server_options = server_options + '''\n''' - content = ''' -
- -
- - -
-''' - - - elif request.args.get('add_master'): - s = ServerList.query.all() - server_options = '' - for i in s: - server_options = server_options + '''\n''' - - content = ''' -
-
- -
-''' - elif request.args.get('edit_OBP'): -## print(request.args.get('server')) -## print(request.args.get('edit_OBP')) -## s = ServerList.query.all() - o = OBP.query.filter_by(server=request.args.get('server')).filter_by(name=request.args.get('edit_OBP')).first() -## print(o.notes) - content = ''' -
-
- - ''' - - elif request.args.get('edit_master'): -## s = ServerList.query.all() - m = MasterList.query.filter_by(server=request.args.get('server')).filter_by(name=request.args.get('edit_master')).first() - - content = ''' -
-
-''' -## elif not request.args.get('edit_master') and not request.args.get('edit_OBP') and not request.args.get('add_OBP') and not request.args.get('add_master'): -## content = 'jglkdjklsd' - else: - #elif not request.args.get('add_proxy') or not request.args.get('add_OBP') or not request.args.get('add_master'): # or not request.args.get('proxy_save') or not request.args.get('master_save') or not request.args.get('OBP_save'): - all_s = ServerList.query.all() - m_list = '' - for s in all_s: -## print(s.name) - m_list = m_list + ''' -
| Name | -Mode | -Notes | - -
| ''' + str(o.name) + ''' | -OpenBridge | -''' + str(o.notes) + ''' | - -
| ''' + str(p.name) + ''' | -PROXY | -''' + str(p.notes) + ''' | - -
| ''' + str(x.name) + ''' | -MASTER | -''' + str(x.notes) + ''' | - -
| Add MASTER | -Add PROXY | -Add OpenBridge | - -
- -''' + m_list - - return render_template('flask_user_layout.html', markup_content = Markup(content)) - - - @app.route('/add_user', methods=['POST', 'GET']) - @login_required - @roles_required('Admin') - def add_admin(): - if request.method == 'GET': - content = ''' -
-''' - elif request.method == 'POST' and request.form.get('username'): - if not User.query.filter(User.username == request.form.get('username')).first(): - radioid_data = ast.literal_eval(get_ids(request.form.get('username'))) - user = User( - username=request.form.get('username'), - email=request.form.get('email'), - email_confirmed_at=datetime.datetime.utcnow(), - password=user_manager.hash_password(request.form.get('password')), - dmr_ids = str(radioid_data[0]), - initial_admin_approved = True, - first_name = str(radioid_data[1]), - last_name = str(radioid_data[2]), - city = str(radioid_data[3]) - - ) - - db.session.add(user) - u = User.query.filter_by(username=request.form.get('username')).first() - user_role = UserRoles( - user_id=u.id, - role_id=2, - ) - db.session.add(user_role) - db.session.commit() - content = '''
Created user: ''' + str(request.form.get('username')) + '''
\n''' - elif User.query.filter(User.username == request.form.get('username')).first(): - content = 'Existing user: ' + str(request.form.get('username') + '. New user not created.') - - return render_template('flask_user_layout.html', markup_content = Markup(content)) - - @app.route('/manage_rules', methods=['POST', 'GET']) - @login_required - @roles_required('Admin') - def manage_rules(): - - if request.args.get('save_bridge') == 'save': - public = False - if request.form.get('public_list') == 'True': - public = True - if request.form.get('bridge_name') == '': - content = '''Redirecting in 3 seconds.
-''' - else: - bridge_add(request.form.get('bridge_name'), request.form.get('description'), public, request.form.get('tg')) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('save_bridge') == 'edit': - public = False - if request.form.get('public_list') == 'True': - public = True - update_bridge_list(request.args.get('bridge'), request.form.get('description'), public, request.form.get('bridge_name'), request.form.get('tg')) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('save_bridge') == 'delete': - bridge_delete(request.args.get('bridge')) - content = '''Redirecting in 3 seconds.
- ''' - - - #Rules - elif request.args.get('save_rule'): - public_list = False - active = False - if request.form.get('active_dropdown') == 'True': - active = True - if request.args.get('save_rule') == 'new': - add_system_rule(request.form.get('bridge_dropdown'), request.form.get('system_text'), request.form.get('ts_dropdown'), request.form.get('tgid'), active, request.form.get('timer_time'), request.form.get('type_dropdown'), request.form.get('on'), request.form.get('off'), request.form.get('reset'), request.args.get('server'), public_list) - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('save_rule') == 'edit': - content = '''Redirecting in 3 seconds.
- ''' - elif request.args.get('save_rule') == 'delete': - # print(request.args.get('bridge')) - # print(request.args.get('server')) - if request.args.get('system'): - delete_system_rule(request.args.get('bridge'), request.args.get('server'), request.args.get('system')) - else: - delete_system_bridge(request.args.get('bridge'), request.args.get('server')) - -## delete_system_rule(request.args.get('bridge'), request.args.get('server'), request.args.get('system')) - content = '''Redirecting in 3 seconds.
- ''' - - elif request.args.get('add_rule'): -## svl = ServerList.query.all() - bl = BridgeList.query.all() #filter(bridge_name== request.form.get('username')).all() - all_o = OBP.query.filter_by(server=request.args.get('add_rule')).all() - all_m = MasterList.query.filter_by(server=request.args.get('add_rule')).all() - all_p = ProxyList.query.filter_by(server=request.args.get('add_rule')).all() - m_l = mmdvmPeer.query.filter_by(server=request.args.get('add_rule')).all() - x_l = xlxPeer.query.filter_by(server=request.args.get('add_rule')).all() -## print(sl) -## print(bl) -## svl_option = '' - bl_option = '' - sl_option = '' - for i in all_o: - sl_option = sl_option + '''''' - for i in all_m: - sl_option = sl_option + '''''' - for i in all_p: - sl_option = sl_option + '''''' - for i in m_l: - sl_option = sl_option + '''''' - for i in x_l: - sl_option = sl_option + '''''' - for i in bl: - bl_option = bl_option + '''''' - content = ''' -- -''' - elif request.args.get('edit_rule') and request.args.get('bridge'): - br = BridgeRules.query.filter_by(server=request.args.get('edit_rule')).filter_by(bridge_name=request.args.get('bridge')).all() - print(br) - br_view = '''
| Delete SYSTEM Rule | -
|
- - |
-
- -''' - content = br_view - - - elif request.args.get('add_bridge'): - s = ServerList.query.all() -## server_options = '' -## for i in s: -## server_options = server_options + '''\n''' - - content = ''' -
-
-
- - -''' - else: - all_b = BridgeList.query.all() - s = ServerList.query.all() - b_list = ''' -
| Add Bridge | - -
- -
| Name | -Public | -Description | -TGID | - -
| ''' + str(i.bridge_name) + ''' - | ''' + str(i.public_list) + ''' | -''' + str(i.description) + ''' | -''' + str(i.tg) + ''' | - -
| Add a rule to server: ''' + str(i.name) + ''' | -
| Bridge Name | -- | -- | -
| ''' + str(x.bridge_name) + ''' | -Edit Bridge Rules | -Delete Bridge from this server | -
''' - content = b_list + r_list + '''''' - - return render_template('flask_user_layout.html', markup_content = Markup(content)) - - @app.route('/svr', methods=['POST']) - def auth(): - hblink_req = request.json - # print((hblink_req)) - if hblink_req['secret'] in shared_secrets(): - if 'login_id' in hblink_req and 'login_confirmed' not in hblink_req: - if type(hblink_req['login_id']) == int: - if authorized_peer(hblink_req['login_id'])[0]: - print(active_tgs) - if isinstance(authorized_peer(hblink_req['login_id'])[1], int) == True: - authlog_add(hblink_req['login_id'], hblink_req['login_ip'], hblink_req['login_server'], authorized_peer(hblink_req['login_id'])[2], gen_passphrase(hblink_req['login_id']), 'Attempt') -## active_tgs[hblink_req['login_server']][hblink_req['system']] = [{'1':[]}, {'2':[]}, {'SYSTEM': ''}, {'peer_id':hblink_req['login_id']}] - response = jsonify( - allow=True, - mode='normal', - ) - elif authorized_peer(hblink_req['login_id'])[1] == '': - authlog_add(hblink_req['login_id'], hblink_req['login_ip'], hblink_req['login_server'], authorized_peer(hblink_req['login_id'])[2], 'Config Passphrase: ' + legacy_passphrase, 'Attempt') -## active_tgs[hblink_req['login_server']][hblink_req['system']] = [{'1':[]}, {'2':[]}, {'SYSTEM': ''}, {'peer_id':hblink_req['login_id']}] - response = jsonify( - allow=True, - mode='legacy', - ) - elif authorized_peer(hblink_req['login_id'])[1] != '' or isinstance(authorized_peer(hblink_req['login_id'])[1], int) == False: - authlog_add(hblink_req['login_id'], hblink_req['login_ip'], hblink_req['login_server'], authorized_peer(hblink_req['login_id'])[2], authorized_peer(hblink_req['login_id'])[1], 'Attempt') -## active_tgs[hblink_req['login_server']][hblink_req['system']] = [{'1':[]}, {'2':[]}, {'SYSTEM': ''}, {'peer_id':hblink_req['login_id']}] - # print(authorized_peer(hblink_req['login_id'])) - response = jsonify( - allow=True, - mode='override', - value=authorized_peer(hblink_req['login_id'])[1] - ) - try: - active_tgs[hblink_req['login_server']][hblink_req['system']] = [{'1':[]}, {'2':[]}, {'SYSTEM': ''}, {'peer_id':hblink_req['login_id']}] -## print('Restart ' + hblink_req['login_server'] + ' please.') - except: -## active_tgs[hblink_req['login_server']] = {} - pass - elif authorized_peer(hblink_req['login_id'])[0] == False: -## print('log fail') - authlog_add(hblink_req['login_id'], hblink_req['login_ip'], hblink_req['login_server'], 'Not Registered', '-', 'Failed') - response = jsonify( - allow=False) - elif not type(hblink_req['login_id']) == int: - user = hblink_req['login_id'] - u = User.query.filter_by(username=user).first() - - if not u: - msg = jsonify(auth=False, - reason='User not found') - response = make_response(msg, 401) - if u: - u_role = UserRoles.query.filter_by(user_id=u.id).first() - password = user_manager.verify_password(hblink_req['password'], u.password) - if u_role.role_id == 2: - role = 'user' - if u_role.role_id == 1: - role = 'admin' - if password: - response = jsonify(auth=True, role=role) - else: - msg = jsonify(auth=False, - reason='Incorrect password') - response = make_response(msg, 401) - elif 'login_id' in hblink_req and 'login_confirmed' in hblink_req: - if hblink_req['old_auth'] == True: - authlog_add(hblink_req['login_id'], hblink_req['login_ip'], hblink_req['login_server'], authorized_peer(hblink_req['login_id'])[2], 'CONFIG, NO UMS', 'Confirmed') - else: - authlog_add(hblink_req['login_id'], hblink_req['login_ip'], hblink_req['login_server'], authorized_peer(hblink_req['login_id'])[2], 'USER MANAGER', 'Confirmed') - response = jsonify( - logged=True - ) - elif 'burn_list' in hblink_req: # ['burn_list']: # == 'burn_list': - response = jsonify( - burn_list=get_burnlist() - ) - - elif 'get_config' in hblink_req: - if hblink_req['get_config']: - active_tgs[hblink_req['get_config']] = {} - print(active_tgs) - ## try: -## print(get_peer_configs(hblink_req['get_config'])) - response = jsonify( - config=server_get(hblink_req['get_config']), - peers=get_peer_configs(hblink_req['get_config']), - masters=masters_get(hblink_req['get_config']), - ## OBP=get_OBP(hblink_req['get_config']) - - ) - ## except: - ## message = jsonify(message='Config error') - ## response = make_response(message, 401) - elif 'get_rules' in hblink_req: - if hblink_req['get_rules']: # == 'burn_list': - - ## try: - response = jsonify( - rules=generate_rules(hblink_req['get_rules']), - ## OBP=get_OBP(hblink_req['get_config']) - - ) - ## except: - ## message = jsonify(message='Config error') - ## response = make_response(message, 401) - elif 'update_tg' in hblink_req: - if hblink_req['update_tg']: - print(hblink_req) -## print(hblink_req['data'][0]['SYSTEM']) - if 'on' == hblink_req['mode']: -## try: - if hblink_req['dmr_id'] == 0: - print('id 0') -## print(active_tgs) - for system in active_tgs[hblink_req['update_tg']].items(): - ## print(system) - ## print('sys') - if system[0] == hblink_req['data'][0]['SYSTEM']: - print(active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][0]['1']) -## print(hblink_req['data'][2]['tg']) - print('---------') - print(active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][1]['2']) - ## print(hblink_req['data'][1]['ts']) - if hblink_req['data'][1]['ts'] == 1: - #### print(active_tgs[hblink_req['update_tg']][system[0]][0]['1']) - - if active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][0]['1'] == hblink_req['data'][2]['tg']: - pass - else: - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][0]['1'].append(hblink_req['data'][2]['tg']) - #### active_tgs[hblink_req['update_tg']][system[0]][0]['1'].append(0) - if hblink_req['data'][1]['ts'] == 2: - if active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][1]['2'] == hblink_req['data'][2]['tg']: - pass - #### print(active_tgs[hblink_req['update_tg']][system[0]][1]['2']) - else: - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][1]['2'].append(hblink_req['data'][2]['tg']) - else: - try: - print('---------on------------') - print(hblink_req['data']) - print(active_tgs[hblink_req['update_tg']]) - print(hblink_req['data'][2]['ts2']) - print('-----------------------') - ## active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][2]['SYSTEM'] = hblink_req['data'][0]['SYSTEM'] - #### active_tgs[hblink_req['update_tg']][hblink_req['dmr_id']].update({hblink_req['data'][0]['SYSTEM']: [{1:[hblink_req['data'][1]['ts1']]}, {2:[hblink_req['data'][2]['ts2']]}]}) #.update({[hblink_req['dmr_id']]:hblink_req['data']}) - if hblink_req['data'][1]['ts1'] not in active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][0]['1']: - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][0]['1'].append(hblink_req['data'][1]['ts1']) - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][2]['SYSTEM'] = hblink_req['data'][0]['SYSTEM'] - if hblink_req['data'][2]['ts2'] not in active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][1]['2']: - print('---0---') - print(hblink_req['data'][0]['SYSTEM']) - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][2]['SYSTEM'] = hblink_req['data'][0]['SYSTEM'] - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][1]['2'].append(hblink_req['data'][2]['ts2']) -## print('append') - #### active_tgs[hblink_req['update_tg']][system[0]][1]['2'].append(0) - ## print(hblink_req['data'][0]['SYSTEM']) - - ## print(active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']]) - ## print(active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][2]['2']) - ## print(hblink_req['data'][1]['ts2']) - ## print(active_tgs[hblink_req['update_tg']]) - except: -## active_tgs[hblink_req['update_tg']] = {} - pass - -## except: -## pass - - - elif 'off' == hblink_req['mode']: - print('off') - for system in active_tgs[hblink_req['update_tg']].items(): - print(system) - if system[0] == hblink_req['data'][0]['SYSTEM']: - print('yes it is') -#### print(system[0]) -#### print(active_tgs[hblink_req['update_tg']][system[0]]) - if hblink_req['data'][1]['ts'] == 1: -#### print(active_tgs[hblink_req['update_tg']][system[0]][0]['1']) - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][0]['1'].remove(hblink_req['data'][2]['tg']) -#### active_tgs[hblink_req['update_tg']][system[0]][0]['1'].append(0) - if hblink_req['data'][1]['ts'] == 2: -#### print(active_tgs[hblink_req['update_tg']][system[0]][1]['2']) - active_tgs[hblink_req['update_tg']][hblink_req['data'][0]['SYSTEM']][1]['2'].remove(hblink_req['data'][2]['tg']) -#### active_tgs[hblink_req['update_tg']][system[0]][1]['2'].append(0) - - - -## print() -## print(system) -## print(system[1][2]['SYSTEM']) -## print('off') -## print(hblink_req['data'][1]['ts']) -## print(hblink_req['data'][2]['tg']) - print(active_tgs) - response = 'got it' - else: - message = jsonify(message='Authentication error') - response = make_response(message, 401) - return response - - - - return app - - -if __name__ == '__main__': - app = create_app() - app.run(debug = True, port=hws_port, host=hws_host) diff --git a/user_managment/config-SAMPLE.py b/user_managment/config-SAMPLE.py deleted file mode 100644 index db58108..0000000 --- a/user_managment/config-SAMPLE.py +++ /dev/null @@ -1,87 +0,0 @@ - -''' -Settings for HBNet Web Server. -''' -# Database options -# Using SQLite is simple and easiest. Comment out this line and uncomment the MySQL -# line to use a MySQL/MariaDB server. -db_location = 'sqlite:///hbnet.sqlite' - -# Uncomment and change this line to use a MySQL DB. It is best to start with a fresh -# DB without data in it. - -#db_location = 'mysql+pymysql://DB_USERNAME:DB_PASSWORD@DB_HOST:MySQL_PORT/DB_NAME' - - -# Title of the HBNet Web Server -title = 'HBNet DMR server' -# Port to run server -hws_port = 8080 -# IP to run server on -hws_host = '127.0.0.1' -# Publicly accessible URL of the web server. THIS IS REQUIRED AND MUST BE CORRECT. -url = 'http://localhost:8080' -# Replace below with some random string such as an SHA256 -secret_key = 'SUPER SECRET LONG KEY' - -# Default state for newly created user accounts. Setting to False will require -# the approval of an admin user before the user can login. -default_account_state = True - -# Legacy passphrase used in hblink.cfg -#legacy_passphrase = 'passw0rd' - - -# Passphrase calculation config. If REMOTE_CONFIG is not used in your DMR server config -# (hblink.cfg), then the values in section [USER_MANAGER] MUST match the values below. -# If REMOTE_CONFIG is enabled, the DMR server (hblink) will automatically use the values below. -# These config options affect the generation of user passphrases. - -# Set to a value between 1 - 99. This value is used in the normal calculation. -append_int = 1 - -# Set to a value between 1 - 99. This value is used for compromised passphrases. -burn_int = 5 - -# Set to a value between 1 - 99 This value is used in the normal calculation. -extra_int_1 = 5 - -# Set to a value between 1 - 99 This value is used in the normal calculation. -extra_int_2 = 8 - -# Set to a length of about 10 characters. -extra_1 = 'TeSt' -extra_2 = 'DmR4' - -# Shorten generated passphrases -use_short_passphrase = True - -# Character length of shortened passphrase -shorten_length = 6 -# How often to pick character from long passphrase when shortening. -shorten_sample = 4 - -# Email settings -MAIL_SERVER = 'smtp.gmail.com' -MAIL_PORT = 465 -MAIL_USE_SSL = True -MAIL_USE_TLS = False -MAIL_USERNAME = 'app@gmail.com' -MAIL_PASSWORD = 'password' -MAIL_DEFAULT_SENDER = '"' + title + '"
h9s@
z3;y3M>i;Gu{YM(819M?+zW=aq0CD}}(;r0V2>lHeBjay!k+iV-WB=SOydc)U_YlDG
zk4IK^7S6U1fW`kz;eU-o|BLhx6BFkbmk<%<5#<*FVp;$q!Xs{BCB`EpE@EN9FDNKx
zA@WCr{H5I;X5-;);RaE#1%e3JXCP&N?=$1Q-%)-4-+l46g8)Is!!IVu&(HkF_A*NI
z-4gY`mM48nWm;O2{{%q#mg*$Iw;^rd>EhxDg}D7YF#iga{|C8$%>Oee|98{>DfY)~
zC76pZKn8XmI^NFzt@-~#@DB}|P%DVDJM6!6{huO#!19mt4Dk7nG2om8j$OXL&fP!5
z;x=>s5B~Wx-2M+*0960S$o~l6|G@Phxc)~7{EvkH6J7s->wkp6|48^h(e?isT)2OC
z?ht37(DMfR^6X1Ne4wYtw0xkZ3_=B2gIX6tDeQm|92a#{cMyn|<@O(nPobO_Fo@*=
z)>6S*!NeiI%k#6X{Sx>w0tl?EVCXZoHS3#5XB%*H;q4hKYW?`26+TOCMa!p7xk$zM
z2~!c()ad~OM=1Jho(@S-oJDrAIOWjg)lBX-A7NrkEG(r!)=#J`IWxrS)z%oOVmJ%&
zI9=3^Vo&$Oy5BZz1n%55DlCQeeXsT8*&UY%@MDc`dYe;OxiURpEXxQ+u>Sx3FK6}_
zrnrJj9HsIw*Z1Y|N0bEoOLo7Vw)twA%en&m%)<9EIjvE;Y6={0Xx9rNZsgVGnLh
z4Sgau3?!zN3bMY(=@|d6B|5dXb2H+i=uZ*lTanmMCK}{RtYn@YU6&$7~S4F)@BmYhLme?G`5YJs@f*-MWD!R&Stn
zDGQ1Vrv?h)&+$nG5>6Taq8R*f-R#)5810zm%^t};ao1w=yRN8f?uY@WsgFWXP7Z+b
zc{2&QlboJgh?%PZjZq!3R8nEblb~Xf7hEz%^6FmQg21u&BvqCTJmTd2r&@zBhZ6kh
zVBuURj2~5pNtFo$sIjc?n-K|TE1G)vb)b7m2mXD|NZeX#;B91Y?v3{k2$nWDxTr6@
zpg^StgwIG&oKysw;$;|EpF(FH&}#XG{ak`4FldpcEbIq@?6Mt^aN!s)yL~;ALI;z<
z_h+G52n^RMTRu;p4WhWk)_>d3m>4TG^V263rj1DJlVx{+WM(_&^>2cfr$n>2)H#Q|
zhFzk0!^?lj_PP*2m#p56L{{OYYNKek>3*TC%wcM!JUor4V!1slv71pucFci$CqK96
zW^Q}FoC!er&5>b%5jykWl3-+Z2-Hmf1dK6>NmD7%zL>sj%WtNXPBb|fN0IiUYRlHv
z+pRg}?9sQ%e0`Cahg+DV;y|wTL5gb-?}FmU(qtK}pV?qp$ww4OJCEc4$^H1_ag?xW
z5j{KgCLRYNV{Dx&s=B!)T|F*`V~>tCLz8Q&|-8sI#e{-yLd#8IVjXkPJwpD%CAZ
z3z{i?-4%6i8jL%Nny`)F>vnt3!jTj>Z7!C}4gsp=_fko>EvIH%K))AS5l8(4K@Jyy
zNFPOzJp
@N&78OX>f|bZz=L=D1GiN8BDUu6=PleK2gE?
zBDdZjN(%wuKQLRgiK*G9iv?ti6(yPx1=QY!1*>;hJsCpXC{fFj<^TY!
ur%}_1oy<^FiwMQ|mYmlslUJDFT#Bp p2@wTWT2Je)aS_$>KSZQmDuB#Q&mH&_mapGFD+DC?`&
zFGHM)TzV-LocD)9asiJQ#IvjsT!v*%sq{`0UCo4A)v+wg6`{@aWMP_52sjC*#s|VH
zEhI7e4k9)j|7q;GX|_3!NT%J#
Sepe8OaNtE^CsPTM#Cfle+;o%0Nt3wVS(T8HQ=|HlwJG8RdHxt> zU&h!EW|`zZsH?n~N)m>w8}MfSC_964IRNDU1hB8T3_JzB2{cMld2@roSe;g&ccigt z-s?d^?3kWjzQ(z%r12x6NOC{)w8_icd;f#{Ew^B{fZhF=oE4zZV)gk;!u-}krlq%A_gr=R-=axN0lVE<2YYCWBhS}c-qY5# zwC45JyCVY`kCi@4xs~!n+Gdv(5`b?i9UqoI-IN( 0RDYYdD+rkLg^7FN`(4R7 z=y?Fv#En>GjYAK`QTH%~dLRKP%ca!LrfsoO`=i-Y6gOCr7o54l5^j3 4%z3&4jotNFLcLxKowi2)sF%wyQ>j{X9n_+jTeoX1i^3ZOB!Jg&I4jXqp|)?# zg{-?yvMe2Mw6`Yyx~w;sn)m$2H1ON&tFG( gOu~knO%`(+~Ji{NzI{t=GO4%7o @8n#O2TYmv5jP3*h zPJp4AVa0-w)>!ouhkTMLKyK|OOYG!VN z09F4=MB&!ri>duqEvxB6YE+76>U?ySGo=VVx%iSxr8Wyb2uVByMdX$4PD~QXYmJ)O z9bbEEfjK(>r?c<2vj$%Rb0oYvh_OuVr|YjcsjD3}Pr)5}7^drt+y`FD2eFphQPlzb zk74LovXd;W+tXH!aZ7KPSw6oa`_89>f-ZHLa@i%8gSm9MGyb)eQAL^C_&q5(?BDfC z(c+#TJhD^li#W8UQc6Q1X2LP#h;+hyof%Z8UM?E1ZLWpxwR=&y16Z(UaHb+G?R9UW z0Zvm5KGVG&^OA!LPHgQ^{xllnTuZv?)A6dkr)>J+UBcpYezUfDpW%d0%zhD7LC9N+ zGq9w#;!?3VKI)B^N^`espsO`scduv#UJ-T6Ny|fUe#eArP-M5zB7CWXN5%46i8U+B z`>&kss4LfdD+WNpJLRyTvK|$KNMM^$ZN(hEj>{kvH>Ja5UU7Ju3Xfj)id^`5u7|$9 zWVULJ)~Y|&3(bwfcp81Oou3+FW=T@}Xj|$kF5!ZR-{0(Y*Cb7IEB%+;;`rNh-?}_< zXxJsjS#htk0g*ZTC=y$;R`iqiVr-H6u(IniWHS!N41ZGyV{#XDuhqxGW-VN#pt?h0 z)hgK1K@vhS&Ajw*d#wjCWGj~mLRY@({&9;O1eAkh>BHhGZ%0Y$JjSEk-HN@SH3^^b zuaJrWK0mu4ojGMIE6ic|Q&seZ%Cj!q{C-AMJT$D?x>L#ON$Gn6|D_74k=>XGtSN5W z$L0kljV3+eIi7r(qUV2AbAnuEJe-wAZJl~v;YAJv+4K9Zh8kV9(3ak%rVC8urM}tB z=J?uuFC%jN?5R?MT|oYNeZ%{cq#LWMhfoM{ZAtxcP<8F%8CbW3wj>ca%J}V;iNC}d zPae6oJyu6Vu;?)nfLXYHf=N^mujRKITUmu>$7wQ6tLl?cGD18C**ef6gD;!?X?V+A zchZBP#OOJM(pK%X=39iY+I-!bUcDCSoB|GWJig5n1Ia!~VGML-t$V;SI~H*w0!-v5 zu&_sLp6{97XBQ^lF430+U66duH`yY85>Lq)&ui9BSV)yyS-em(FB>Qa&!rw%X0LK| zv-yGyqwL!RAwBxHBWkUG^M3lh`VUt^h%6rWVZK5=fKk)Y4{@#pn-l1;d@ajz8!WOz zdZ0B6t&8n raKy-s`yUlCz@P0A2LMlQv z;Ls`sg^{JtQ+wwqvft%S^V`&Pa4WVF8>wm#NtDFFqTAXgR)_z#SOT*k{9leDc`2Am zd|kQi^JW;3y#-reCI3aKxz|em?>?hK`-%AvhCOE z;}kH3@4k)1LTqKsnlAV6voHEWo^7QtvPF6=7VYQ#wU1r`_OBeI%R}h=U4J_C^m`mn zR42-|OOB&5{X5Jwy611NNPw +`?B~o>Xg911B_X+bfC _qBQ^abJdgTKd>U-a2$YWZwK*VrX!(q!KA4l9DZ X2VFuXCs)yEx@jsXqtEj!CoGoSfO-E?6vF9Q o|9?I;j|nJOI)^9DF=ty#@&YN5Ed>vE)MYN zjV?P?3>8_}ef+7%NnLUFKvY*H)4WY<|LMLx4 a8DQqR zMnQ}vo?@=*ejrfFvSpJ-Uo!2TGw$BM$6rzjUH{0{Bp&n&JM`rnLOLqo6GbwWrK{g7 z!maR(CnS*ioe2j;9DV_XJtU^Bu-)`75B1h)OHE4ImL7#gPe7z|0n842YW{OGL4>H* zHOc2n5Ld}1MA Rv1HQl0Vuhogwu$+SVD65mMxA8NDWYkGSmBzz26 zSa8A{z}?K_V5KSd*L!Zgox8p)jg;GRjB0-)`buGsZ(vcn)^HQ+;HhY}DG %-JdY_dWN<>&BmvIEeAfAawceft}9NoHatE39E^aM33fjQ3#k)Utva4GzZf!vaW zKZt;1R(ZA|EulCq*-h6Dp)O8=eczQ>K$vT|uNIboQG>ZV!f(%aV#vGhly-KFqs2@d zb+y{88l217_+ex_I|D`C)9sN%RRazn8@?jUc2ngKn#h=rX4v}|9$@{tTWz#WzB` #a|+Y;1mC`j zR$l)&3?e4tlhV1waR F|A9^E5&jNQ~%;%^nuC=3C6*R0=)sqkT0f k}6mMdx|wpLeOgu4zFO1iO_W$ z4tT{l^fXlCFi}hp`+kKd|JEEY4UD8G^^C4?DI^w?pbje4ufUoi^p$*A4^^G1xTIoD zYdaEXKn(j %HU8eF@mQFo{gG(* zvI4(0B*-n?6p>l)@@;#?QkpRb{Bj)l(Dy3^qgzYjymHIRm)m;F-_k<;-VoBD#3Q%Z z(v;y4Nn^*on+(@LkaoH%>@L=|rV^{tSS_N#Cb3Dl44&5^hcEg?*(5d<6~b{&(){O1 zh^4KT;8z|$tIr}JrSg*preu$u&3DyFg7YW|jKt5;5)Q|xn;qr%yD7aHjnzG;Oz8>D zi}eQF;Ngr~#2Y_}l+33&AHW+p4!7z5ViNsktV90!-k`12^&x694k2MCbC*CEkJ+MS zgyVt|lCZs>dhWwQ+Wr&a)toHP#L~NfJjGiKtFrQV5;BX$3;XGdf&@M(2JgKsd|9aD z7H<5Uyw!5KHQ@NZ)^>*`Wq};?iQr+vAi%6C&+}PoeI_N2@j@?EWtIJYy+9DYVg8bT z^{|=cDF(%I$hlLGS6qXdAUwIN1H|tAAQm`_Y<^D&QJ844+}wR*&dcOJI+ZPMw7Ikp z?*98dDP|5xXKm0m-@uKk3@i$04JyFT<(>JZKZ*0LVaLpEBN>PV$pZVu(Y+r4G+Wbq z@i}^dXaJJ~t%sx5)Fy1#y=_JvujQnL53(|}ryA;{>fc;6< |$M6>!12Kx*Qnb zYT^vnKRqq-Y~zsBay+ZfaX(0RR@1nI0}Dl$g`U%#B6I%L6UK*?EnOHdtAtIlmHs$n zH#)!!Pmq}cuz1c&u`9zO+%z7pll4r)?0`c86wniPIL%wFpUxJJaZ{%MC|rE)x$yJ# z+1_=r=223yojI>fyTP-vhOzQgGko5PjQ%)Jd 6vdGH{cjFZdex6Z4S-7AaiqJ%K;x>^WXI3AB0>H??dg5 z?;Y(qSi3T4d|si#Gkc7FEx8|(z96}ZW%y?Gjj!ihmSNj5M9uXE;UDgWm6_C*cDXHq z#MQc0U3QE 8Js1-jb2R!RWWB2>P)77WUQ$mD_0d7MA~xui(!;U$?cgc-W#8 z4Y>kTe{fpKsH8R~p!@Q97ET&Z)c~T#g7)zJaat{Jt-KdH9$h!}h7V&IH5lJkP90o| zb<~q55$aUVFJ8t9^0MrbY^xk&qbrVoQZAilQU7Nn+m{-L2&Wiaom)bNR-2#fXGlKg zn9F={cj|3_Q(Bc};vYa`t9eCuq|z 7UXP7pMKoG)RSQm zOZdQD=d%)_yU)`RIj=jbjwPIU%`vDQSJ=Jj5n}H(01X+zA181YZ46!VDWx_g^XvWG z^-Y0I=~thA{tDcRXpmSXa8DkOIcZq!CNB2f#`_)xELz0-2hbovqngl+COJw3r|-t6 z9{08Oo?cCw^Jf@7jvG8U3a+M0Iz@(m1NNkD4gWKr%s|3sUsO}_m};97p x+HT>Ne8B7HLj>TTN5LfX77_ix|AOb# zWAe@<_`p twH-BVxu!3(*dmn5=cW;ATIU~DIDI0iU(zOwJttOU*W!(%fW&p zlwFnYpFh8Ok@o8@U1;I_7J@QVRk+Tg$3QstxZd+EJ(7)PyiK%qZ^ADva;Q|^y_NRA zGq>3pK$<|tBTDzBbAr>{op|OzJ3Uz&=Gd89&Gjp6^EM`xes4_JJMhr!qi=4l{q{Wv zBxAcKFi+gKK~5{oFZpNFs?4L0buP~^|9RvxpKVJy(_t+<>Ql&;sbQ*jz$%x buMXgt z)0fvQ^hvgUu{I&r+LLC$mxvcUMu*gmmwfbUhP=KcMb}+>@AQEjv((^|Yih%QBX(Uh zCH|+u!GnqwrS9_TdZ38;k3G^#CAbt3XHf0)(lR8i&M%|qB{COJJR3DFDJ)JZ64x7}Bj<7I1 MclFy+%*($b= mZ-g^=!C1p}tyf*$li Ip{oDee+wH&W*HiqNb%1i zBkBVb9P&O078Wms8y|7Dh~Anljck%-ruy&`#5G^BcQ1Vj%hem7w=W~r1c5MVn0cIh zbBNN0g9x2-Dy3TD8(Tm;75YE3o4Pk%gC|8LHSx-h{%V+hc&$)EX+lrN+u$(D0%n@M z3A+$%aXbw6J4ij`17UZc{?wJ7(cM>4jTJYx8*(V)8_uvviL7V3+37$s%6Hm)PDIb~ z6yK;{?Cnx0zfvn^ e(%!WnJj&GuE|8gSv_;sc%Q zld1NI;S$gg17oibKA|;zKZUpqw@BrMJ%M2I7cd?Plj$ptk TN0kx^Lmp+e!r(OTF0) zEj@x_&eKS=&mEJ>y~vF}?ui!YT?@Mj@}pSk{^n7$EkchZ)o)*GMSwI0@;C6W!b=E( zi5g)(Y$fc0@VH%OKmqp YRIWCX4Cfq7`6#0(>K~zoknf{!NI#_*JK47 zD>wPJS0+ZNkxP|CO~;8Jvnv_4wfG;@gP>;BzT9XT%!VC%0Xp4hQZV_B;O3b|*l3V8 zSkT^rA;LAFxB{SMH0WHXvPRkG);|Ek>8!;5A?KxPPj!&9h0Tns=5d8a=%>2>#B}Um z)!y5!wJ3qGom9JnFc67J`=~gqO}l8jtD42y2juZEOKRPIEj3-?FA*y^o5X2H4?4FM zbEPS5QfFba-V)4LPWtkz3HpD)!-7G8lLTlOwVY3RRUl7)t+~gMCdSYfgb}Og;z2oQ z?p2BfivT8EXO_=})AFD-8BI+pix8`o%#z?~ ?n=vk*t@}Nw5>`&%K3BDbiyW@g{F$$3x3GI}*>Mmj zXa=h!Bq(eOw7UW0G%3{ktFh3!M5u37$Fd^1*oX3O!h-XC=V!lA%k6gAXq##Aq*{Fi z*+~`X^tX5qs=V78rzkoGkoO997Pe2-fn<3@C1C~k#Lnf}3;XGs;tMbm9e&+{iOp^h zUYIAAL(TkGU7d*olYH6(^^)i6wBaLBe1R0vDW$P wD1{gWI@*> z2IGfbAtbB^Zv_OmTC)n7&(-?PH#9^!?-Ag 2ByI|$)TkpPvw*jrtE+(devm+MWE)b`d_$tmjQHPQaImaW~e z66**tTAsi-%SXl{N8K_mepjgFNuaLCGwb};ig_EPV -X>&JcTn;mf0 zKbXZK)aiPgrK 1H_a0H^ ^Xzl2Adfnu?;j&U0etPp9T!WLJ1=>U-FeHWD{wqX!DMiKo zHw(}@U3YWAQ^dY}v;dU4;;k9!4vCzsrsim>ltD(Jd>uL7#BM}P&kgxB^`gV-%D(gf z3745EcYek-9VFqItLE}5<$n^wNPPn(zr!c)DI792-qF04sl=c8UeXbaR)1nPUaVs! z>SCBH6f 7!&nB6>X%Z(LR#AAlnr$MYGF) zEWA MGu0e$;m< )?Hv&FfQf;o~u?3|t z$@}tKk>I(FA0lZxvqt!P2ZGM`6Bep|GBr;A_~9%l>npb8WFErG1Vz)#Lyo^;T*9$m z5OP?ys1sAG-?C6Sqnct-P^_Nvt!7(+tpC+q(QFE;dA}ZWbvBo2R5 &QO z?VtZ`-Ce!;d_$jaQ^GJrz<72K6Z@M 46M)P&Oi zfa*^aN 8| zxESZJ$_`3gHjm@3B^@bDi9Hj6Ix
iHlfbw#PDxwBR8&- `M|O-|#W5Uimv ^1@s(;@#icU@JI-)GOyLj21}b2+x~a9R#+R?F(SQD$F?KKX-YR&~5u zGp=3l1DzuRXH3Pf^nn_~V1RsWssm75{pK2vS$CzY{sPJXga51yE#6vIPou&g`9&Fb ziSJ3})wqJZ1&&^j9l<4|PQ^SctH39BE_7hhC@8cK@G5aHbOoKV+ucyIXzuxH^K$sC zvzcKckqo))996G; +9+7C#EB0K3o(-JAi4c!c+MN zB8zsHbipBK3psPtyU+NJd|bs3UAE4zs;+$j#=R NOZ= zvr%@GFYK#zQh_@$^^!^A=9w4pPU;DRl9cJc;I4-@XY)JtR;%Yu Y4fj?XK58+JXMb*54kGl4t|s z#Q~d9*xcM2bY%YP)j3+7<^Bq}2TgAp5BVQ?V&qALXoTBK56--B8=EgT+8q@!w9gg5 zxW(0?!^-|a7L=nE=hrogduEcq@GB$UoF8{L)OHnw*Ag&nb^oK| n_CQ6&|?hWWID~4)bxK{)*$hg2T6R#J5sxx#VPc JY_kKI|h9QTgU}W^f?&jdv#BntzLGPmFA=-Y_ix(;7b*E`|nrdieas zlpEcJQ_H;BAH`?deav%Gq#?PXZo2elPR@s7{)(ak{o|wG?hdH?W-@0iQw~*p1X0k* z8==!t8UGR&q^z;BP eEXuI7RH2ITIs^ 21a zIzJ7b*VL4(mWZ!pYJVK)q!UHkV~^_4Mtxa5{KB<9y @nfo8u9~0Sz$Oh7=3iSxZZU!|b@o)8qGGp#1Qk zsPR`IIPd2)AMWX+>W{vHg#lxRE$D@FuaB4enhqIH#kaY9bUt;bi}0LVZrO;dr?Um5 zW3;na-VSHGH{eH`d`_h}ROvfnv+jJ%ea_}k2-2vRx_ ~k9_NY8j(Xql8dx%wyr@>0Q1g=D&%O8b?_Su zej6okG5RL;O4`M<0i8+KP#`Q}J>!+_EUlO42RGv*s-r63m6)zET=LH6i6Z~9FHD>X z0i?-jK$bX&$E9U!HV_(sMeT#X*Y`t7+6P7E>CI{TH5sDr2LoBvN!Yj5#4y7fH=F7j za{|ME+{{C$vIkY%+SU5{bkd>oZtEb?Ix#N#*^S_jKpFIT>_FpYe)~JGfNR;+vh$wL zM@@m>tS}UA-hWtdO)#sI5}j!Iu&jXdPXq>rNhHtd>I*aGl8?Jb8Wv=}l728QxP?qt zeuMcY{XQYL0qCB&lQRR5+MoUMJHcRqwiaM8^42{V-j!S5y8dJ`YF&eMYTFbBcQ9^v z{uf<0l~}yg5G$Uq4ZyONfi*1DdYwn!^@eGqXnETmy}H8vy8AUia-j1&iDy;)E8MnQ z2q&2f?6=EVq1cwgaf;uP_ws_0MWc6FM6r6#e^~~`0H3l-%ZB4QyOo-DL-a$sob{s7 z24QXSyVY~=eDup&XV-(c=rV9-OG}FWs}Ev7T&rJk?mi4yg_W8M4RR&7-xEq&hrOo} zb2e!^{ )c;V?XAphm5aVRb-~&aIGr@!4u{EpkpvRkv`{<|pX>FWnQ? zrUNhta5N!&VU=BC-UBcE0zm&et05!dNq?@{Mq=ws!DesTudZF3VMP )(}+UX%y%1pxRf`NQR58JL#;*oQa<@1p4nW>vk@xCS+mgQI`)*>W78yl=vAD689 zg@^pI^jfE^h>tF->E^ ?~JT~ z3w*G2cE`~35|u>nB_EO5Rk=4;%qMp2lGk4J=}<;o9UIn412(q@^ V!3KzfT_CgT6d`7e4S&t -%hOR#it>p`DOi9K+E{j}@Bhh4qDbxASlc0tUvyq}KsW-;9X zlTvHc_{wRT#QONO|I_8PdzIjV(?0g?f>KAkXD~XlUm8%Wq-4Td&nsdvOJ?44q>es` zv}XX{dt+~O9D7R^X{7t$ynREbL>U1-hco|AZ>z<7i-zngs7D_J_oX`Fd9&-yHI@Oy z?!tVLPSe5pz<5sMr#sPws2ZMjL7Mz=(Vb4uLq5C$d)`sjJm=#hTh!?RY$85N-VdrV zf3Az7BQSO${@2aN5RsRDJx*XCt@$kIvD!TTf1nz&K;6{Xw*RBs{91gb+L6O^;c{Ti z? H$h`=&0611|c% =kLf9#UufMC6G>4p9F$(7^avGNv=`N8~B3-jKu?CAYq8M#41mhEg+ zh*SNlMnvrnDou25k{NBw2j{M_%5tZ#s1Z*$^Kd`i2d#HtA7??IK=RIC<_b>>6>aKp z9SH-Zig&H>H`j-nVQaqc4sk~WZvZk$_caTC@`>wGX!Zf#2cF`vo@7UP)VoY$>?P9i z=>e# m6v@_k%>Wc$ngoBCyMd*z+X zJ|1(r?*Y+I_kA{8s_MrBp$aX*0Ti$rSk1fFn Jbd=U%Cb)txCHU-WpdArB2bRz8 zUI-8KRadQ0_0j!q-jq2JzY>_OLpkxhuQW0Gc=V3TIp(jECSX^HS=u@u?PTYkAd}c7 z$I6>|arC0D7-3rXdfzhVu1jxpc~`TZJS+GH;?P<1v#=M2YZf&3y_uXI)f^=hLz1Sa z^H8n*+;qo9;@H7BxzO@lqhKsAH2A>;MSQ&uX_hoh3g3ZG1Xa3QUq335|B }oJB9c99 DFE= z^&ngS;Cg!s)Rr;a3Le3^T%^abuW+J@kiC?brK zcsONJYFKP_LFI2T4hTlO+UerZs@$~e=0eFS*N_lXmkUU2-?3s^9^s7fL+ zjkVzo%D`=(;fXr}4d3Gq4PI$9FdKJmuW-qUsB2v-QMl8a5ql!EMRECFI6q?D35Ux6 zo1MMMA8$c%V9rlQIQo5NH1aZ%c$;0~&yFH-cAv%v900m@&%Bl{>Hq_GQ8@pEAM_rq zMbB~1pTS09$cTlCE=zu-b$g$jJ>b`fWm_+&___TC*Ay{w{yMu2z{_{_5_^A2HD7ks zY_L*p^aC}Lhd*)*E#uuP&+KWhO~`n@%m*SiBEI0r*XQ**!+slXe}oqMf &*R#Tu1K45I~6+pW42lV0SaX)p!y89sX0vHvw6dl&5fx%6RZpydzYiP>;$ z{T_v%j~1N5_SIHdlKy>S&pQng9B0rndLdG1Ni&L)qF$~4w$93~_=?ro;A|itt2nI! zoAv(J>H0aCo%Jj=Ous3M&cOC1JJnwaU@~wf_JW>3-^QXqRei&?Nl T)3)e`B5eKCOy5mx>xm0{Q}x1w*ePWn&bOH@J7EY6)>2 zK1r%C%yHpv uSWrQiTUYO|uTxp^IMBbEn}!YCfTJH<4u;3|1eeMd z$AYsN#!nFiFfT ouXCC9~~={to~&M^Yor6Ys&__JEiqzs{d za$@Wxe|POmKufHuVn$>#eQw|r_E7dprtE6cS@b<* Bfzr z@Lc7V%AdfuWikKaqxStu3Q6EiB28Saa&T76G!_>z8tTQM1@9M&Kj{1Fncm-k-e)_| zA*h^K6Q5`N4%R{akVAqyhvobvanGPJ7O0li{l_Nr-*8ZQQUHU`U*10nK+q7Np)Q0k z!A=yB<^Gi0^y&SLa+qfDPzl63B*HfCpCmkJl!JTFCGDwJxLN*;si*QUMCo _ Qq4)T zTjO!fOKxC^CI6P#ps1vP#e;`bh?kE(#UBMJb}2>kr=Bf?0kv~Ou>Z}9qRb(Nc?1JT zXFNsn;3h{A+QWq5A9yS571L8nI*aPupsA}v;GhcuYH&7WmH) >UiH6bZ7#7G{gB%jYiT9_?7BRKvx{IPovbP}$xJ zT%`sWSi$g0MM|jj(k^iC^C6NOQgXI(;ft?gUGVfBSQfC8yBxP<+%Otgfx|UWW-!zt zq-pqPQ>)Z~rM1C#V^G4g_&RrBpLM~ev=8?ZF6j-ZN?)$J^_4Qp82_#CrT%z|6|UWG zOoX>Z`R}>#u2Iyn qFeaTd9C`3z=NDdtNj!)gYQilHax^8Mi PCiemm)+++UV^@u->>ow>hwHjO{ae<0%oU=&e4KvzhJwCQp#@U(Up+px4Iw zynmmT@E8q*FNrzGL1ppOFLRZ@MRnXC7>-?t6qkLPUW5{1*S`Z}ZiywseXYa<3fcJi zUmI=B?^~*u`M;(%IPl8##+mX=LzsIeqK^@8mEm&<&b5mphKGGJ>fc`?c&F zLJR;M?qE(Zukuvc(akdPQd_@YO)iX#O9DF2D)G=zvDGJ|h82Zq-)+UIWZd+6zd8;5 zQ0C+aBCM1R6O44Ifhoi`prp$dKPAD?n8sQJcWRPgJUfH t9ZLBnW7EqT~gd@l0$JX zs=2Yw4 8kPGkV7X3&FA!YK-vG}uRs#Vq7IncO)c$INiNgifnx}8(P^N``(iY*Yg zM^W?g6OU+DYDJqAX@}xchD^4{e6mUkzc+*yG0_XlgWL%zqn#|L<2kxYQQujykpjY_ z030RznC8>pN9%eV7f5AE2V9@6or(QQcRn*t$o!c>a|Mre WYgxlJ=gi3ulw1j^lOzQJt?b0Yu@+DDy=Iq9f~~ic~+qpXm(qOg%PJxT35;tdYc>fdgH&muxru@X);@Q zUk&B9v5@(0X3P-Ab(?q BrDoDGFRc5Zd;=s_;a6#%> zEz;*4;f!Pi9^6!Q#5#(v1&_3*X=`54^XZbiDSY5aizNYuiQ!C(f~Ngx1S3IwhT%ND zRv>*o(#B}Mr}eo2Qe1k>xY#(_^1oUDfwb;*qK4EvQ*yVjEN8Zi{cnMRvn!8}#dS3q z7_A}b?oA2{d0Yj>5Qr8j2L*-wx2e^EKziVShum*k#Y+(;nY8}-c&1i)4&&aIsq$w} z0hF#u!evx|pt#rj7Q`e#jbK92Ee5;qH%-R{KxSq`f5Lf`&WHjH{B9xZJJSZUI*0ap zm6FrvLQI&bRSqirtrR$?u?>bwiX1NJOZWq(z}RE#6z}&*Q-j}w$WlhvREArmRD^5| z6+JbS6qtaV5Fe)AjKfUq5QR!z4yT?E7P{TSD(tu=mZmcAjb|`OYB4WwgOeLoo_mTr z4cmw}>5X#{z;3Q8N*N*?%YHl=mnR|kc75l^s_Wja9;5~E3fUhG4f_P8aSGsm5mw|S zr# n5We)k%ifzJ>hixFm#brYn{rXYbkMoS6 zvEm4!nn;ecn|r{JF#)fKVj?;d+_vx_5`ZNin#Fw07fMbk@@J|{5IkL^I$nlx@4S0+ z?3=3xNchY|-Gcc89%ZObLr=KPZwZn&B$Qp%_GstJW8mhmioc&KDU{88 hbX{q$wqUbB+0R_}q&R@oxfZdWx{OCBidrc^2Rg z7Z*3^SZi%0Z>mqH_WfjfBGLqKDps}lj)VZiG0X{QR;z#4P-JX*EFI;_XWx|l%D#?p zgYotZMu8R-NV3Ah2jEmlxhb~S
g$Z}O{VV{HI_I+t0!FJkzEp@- i593fVGzy-b9Hd3w=rO_8x eYSm1e-?`K2dk^-e*lO)mI3%h00I87Q-<@y8mx*&Q zzGOK4hLTTk=vQ#H~BvrDQ=X@_qS2NSo#SmIVxptAb>q@oi hVz{a?~c<9`h2tlyy*9LQ1A*T+~h#{}A1jfw|z~t&n(C-5u zdS>7cd2-9v?|a4FVpa@d5i5oiF2zFeMrojsy6JSu6wX~$+8nCj_?QF{QrzK6>2hRv zu>{DSLzjS$21)3+sLNiMiL!JdJZo*;#yCU99DDo}g6pefbBms>>p8Kmh(C}tylvNl zl `$NqQ!kWE-pCO#9$P*F?FOaQo{<+ z*!KKb71H+(Dq1*iDO4(xg9iA{0KtG+{O03i8u4~}oXdERGyZ1v1p0X3>TL@F8j68q zV13N9lDeAMhjvo`=sl_LZphPbfBkx;!?C@kRl4Luxzs%f?SQgg&sw}A+!N_3DpGgd zxHW$;Q0vOPzfg%tyF+7|Jlr?dnNYtoNB8fl+Xr9<9ZLw0#B?e!t>0X`0aXjP){Jw5 zi7^D<;hE5vyO3E6GK6fu?5+9CyYBM DRw@yP66&F2BwPrUCU(N;bh@Ar7jw^X@zqk}pzm zY#5>iskX?0r$uP3S?>wVIgiMe o+Ku9B4BE=3qNKqY(swe8r=TG0%o`fn34lr#dJs5 z)Bc-7#3iR0&KGwG8Ki-!A7T_fe7~#-=Yko8(}e7YO{&DZSUs0S>OyUOGa^&w#xUaD zMm$^QOioxS|F9rIAS!%d;Rk|`7o?hLa=(ACw@M-`$k&G4mcFgJaYZ>-y?>lY3>){T zaF20Wb42_wH;Pc2(>B6adlC5S2{px=YHt9CB$^9tqya2q8tL3gxNyweM`>~3V_7>b zR#sA2oHGc~1QlvM!?9rrAqT0#RkrIWRK(6Mv`S$sh5lg|IcTD=5MWaQhv^lYdu#Z} zx5WTl{{#n?lm=v_GUGe &F;*5%XzSEd^oyCTxwusAl?_&?=NQunj;Zol1@<9> zG3OC`DeH%ub(w|Oh$y&%PXj8mzQ|d|w=~om)|{*}rsNo~_EVc%zI)tyM%w)Sgqtp{ zVtpkv#r!t10-RuiY=x$y0L`i}Efl3;lJTu@yBbo_gPZp~R`ioQcnCZpT+y}`Cgfgk zr0)ZF=gXH)Pj8zu9CGq#9*?3V9)8_j+nsYfF8Z7!y-4XcD5&T}B#qkS;LgeT{8u~} z3$ T)FKw&H2{iPgM2Mx#_RE5(l!-_dm7WFE)Eh;l z<#;LYs@l0p4P(N 2Zr-7KHp1sipiW5O+Pp@yum_c$vG7a2h3m#%@eJ>D=K&3 zPd>6tUE*g_^sVs@1u*-yBzjCLCK1bFl*JJu5;1qgTL274!DIsW+9c60@sBtW!=i>M zHradeH{DW-P}sD;Y!)icMaiCAYV~Q`2^62uwqP{orr4&Y&GYt$G6{7c%H^wREb5aG z0sdt=RRX?Y6lzy~0tzMm6#n~s!F9M7j=Pp5tWfn?D@&KOZ9`%*k!{&8X(Pp|aS_(9 zj`@YZKD^WmdC?AciGNrm?RoO3HT)xYRZ|h$@U|twcyb7RzuAhT5;Kqsg0ueU4@jtN z2_7eE9EQtIr~=QqoDYhG2!?-lA%-LIva9Q01unmo8ZJa0CSOCg3{m!*8@qgMPqh?3 zo)ue|qQx4B^>RIAM#~Rf%_%st3I2pVNT)3BnGll+XcXWwFX^;|%x(~^VFi8P8 0*BsIJ5l^%BTVHugHOhwKr7rK^aOz{ zcV!@`8_{SnJ4nWUFOH*`NGdxljg7%E$z|>N 9yA4QjxqTw@?Ngn8z<`z^Gr}6kiAd!7r3X zLD70Z#4>EsFL=<`#>4nimOOflGq_+3DiQf1qpn!`MNbuNI&XFyVZ(~M4`-wpOv1G? z^aR;hLy1bd@60@k?y+ L1o&6^@wpi z_q|Kyu2ve2gZ@KHC9;`#PT8-(C^MpOMh+^OgPBK#5O7n#a100)|w?6=L z?Ol|MhhZFujy%~f>)UVf{3{A|8MhrWIZDOAKHsYYBzybd#5t`uW+$AQ#AK-+dqw4h z&rzidp&+Q)v1oUEHwfCbPUMr&`F`U5^1?0gFmWYrrLmwFl%|J-g^nlrzWdFH(z;1Z zIcgm%$HLOY?&c 5fP=f$bf$T<_`R5)(l-Ey3Ztpz)0@Iim 8Ws`w)?UVycc+=X;k0N@$kwU!RZlbH*0lWiukI_3|Ke^@^g`lZ+G;c3EA8( z1lL>9?{LAO<;WE`- |?%LUN4* zf6fcf^xsckK76h&)PJ~f38(Z1qo&IuAVv``iqDtcFth3Hh3 q=Y_b-A1YpPfCR_ z;1jP{n#1caA3ct28JC<|n32oRFR2454c(}K_`FE =4FZp}=e>`u zTfxFmD+1zObFsp29D;XsK;d_b6fYRnk9 H9q6rN88;r)rI78+uaU zQ1H?5IC03P{ex_IWaQ4Tp&eO-N;z2tc)*NWw0U;IEZc@|$;p;^E>dFMWoF8X{Ux0M z<|W_wwR7}@*_Y}!?H4NOcoH$wjtj+Jwkj@p8X)O>hvRdx r+q>(?~uw8->5fQ54_<3%tJ51?)Ly*Yy^#EQ2+tpXVO)T4<=i zyNT#_9qFnKs4EK3dfn=|dTafQSmN0}4T9#$W6F12erUF 8Q<=#IjIKavVkKff>GlK2#rzb9^)>dus@t$Qf8Hs#I2Vtl0#ooXRyusM%8uDo1 zcNllkaj&0sYfesv+YjEY^imt*Fgb2*9EOmBb~v&503rqG3v#Vv) sZa6E=w7Ej@h zG+m ix^DodS0;s!vV5$R7Rpi1ua;^Bk+P)To<9PDNNp{9breHyF5&la zP{VdkqzX`k>P zNVerNM}T0?_0G zp4@F@nTxEcL~d;WGxOfP0(QTg2F!sjka|G>hwe`x_jboYneaJ$3DE3T7_r6 KuXvN4h#M81B6u@`elTm%Z$uaSkkydfocLra3= zeTW`{r%T$rzHR HzfN%jxQ`1k0lpAxJ(BS;Wkia$8F2uQ)%d|xb@9|1RmNNE9pMY(&XjXp#x$#$ * GpKcCZOK(3!d)4{kqR`ek?XxTjI6UuUb^zsH1W&~qwkAxEI z-MN@7`gJ2Mx=;l?w{MO~XjmDx1*GQc8XH4v_pB!5xzhdfX_+FN+AU1i Getm;eY7|@0QW^Lo^_?gA3lCFC zl`vpCBH7sd8ONJ?wAvd{JGRGyRRz#G)@GdaM2rN(75+<3QFlYd5)OQj(;sCseH}b) ze_sK9dlQ4AcZie+tuQM@p}4RBY8?vhNLX?R@qgL(KNM2+WS%Ah>JQup#Q;VJr_XRN z89i6k=`Wv`VZu^m`6_w}5CN=orpXoG{vvA;-C}qATw|^b{zv{6!8{tOG+W B2 zTwt4>;P^mLI;X{h-NHh%lyf&J=x5BCu+Uu?0wvfxA07U>9jM{LT?Lfn*%2z_Fr4 zHB(biQ@frQYnsIe0SMDOqJ_t$(Gbl>-%317ZjXP!G{U9luJd}*O#?*>NSll06e{^m z$W_}=ZJsFhR!M$(YGD-qnHznL|I~`!B$mu> dPa^l?Pn`6=2t)48@px1cUc5m5Vt55|;j^H~dGut-D8d$ChiO}RS@&^KQv)jk z{IqO@MTbv>VQ$Iba$cSKW`*c%DStj)2%nKQGdlraYM~Pko=6a1P0wDhP0!i$>@O2E zUo^`JKMfRFgE=%96}-4~5l(8s$%sk8R;6FmKs15JZBXx)-j+)D)!7_%Hrgye^q05X zJi7t6MX$W0-G3DzVe&5RH(G~%Q!Atzq^YUq*jVHk8cX=B$h|~IP;=f3QUZ<44qe&r zKRr@%>1Swi=~kx78&T8OkcBIW#l`T_dhOcRjzZfx@nkBv E4#V*IL?t%J%98KCGzK`osd~}nG~tN z12fhsi+*B;6x)t c?O=fqdKYD2Ka~<_CvkwfVB9V=Fs#3-l zoB6J#y3r=R@T1iEH~+GDYK|O@GSe~+zfC&XfP3hmUt2=e320j;B}HuNnVu@HZ8E%& z;*C$4O{Gs0-Wv>}D7G|4adIc_{U48(5(hqB9E28D@r2W>IPZ0x&pQEs)UB9^<4;Cm zy(K=D{5H_$+j3fCFnA@Yfh7(a%+_p2)mONCGZui+`gU>+?IjTly#O+HR*1*=Z->S2 zn+yz h$cc v-6i8{m;T6|TuJ-8mSg%eJj?)0|F$s(hR3=3;4@mT4)Dpw zT0;;YW?YwA{K<0UPY4m)BJ?f-SOdZ*VseMgsTI60C912T;V=}=mlASp-NTon)w$)W zhoKWd*Pr+9N_a^<3)8Ld7s{gXZ!+vQPC-Adph6`ZDLD8Q?8oln2VH_i(hDlFj+@|G zdP4;g5UbOPu`ed=+fV9z%nn-P3(TTm>TzZ^fi$JBTyjXk*?r^b2di3+3Pn#&^s9mC zBKt4dotcOao_pcb(qlw`*`xZH$jX-^fi0b!+x%p~r+VE