PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjwh
LS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPjxz
dmcgaGVpZ2h0PSI1MC4wMDAwMDBweCIgaWQ9InN2Zzk0OTMiIGlua3NjYXBlOmV4cG9ydC1maWxl
bmFtZT0iL2RhdGFzL1Byb2pzL0NsaXBhcnRzIFN0b2NrZXIvbGVkL2xlZF9jaXJjbGVfeWVsbG93
LnBuZyIgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjkwLjAwMDAwMCIgaW5rc2NhcGU6ZXhwb3J0LXlk
cGk9IjkwLjAwMDAwMCIgaW5rc2NhcGU6dmVyc2lvbj0iMC40MiIgc29kaXBvZGk6ZG9jYmFzZT0i
L2RhdGFzL1Byb2pzL0NsaXBhcnRzIFN0b2NrZXIvbGVkIiBzb2RpcG9kaTpkb2NuYW1lPSJsZWRf
Y2lyY2xlX3llbGxvdy5zdmciIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiIHdpZHRoPSI1MC4wMDAw
MDBweCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpjYz0iaHR0cDov
L3dlYi5yZXNvdXJjZS5vcmcvY2MvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1l
bnRzLzEuMS8iIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3Bh
Y2VzL2lua3NjYXBlIiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRm
LXN5bnRheC1ucyMiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vaW5rc2NhcGUuc291cmNlZm9yZ2Uu
bmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAw
L3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogIDxtZXRh
ZGF0YT4KICAgIDxyZGY6UkRGIHhtbG5zOmNjPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy8i
IHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cmRmPSJo
dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPGNjOldv
cmsgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzp0aXRsZT5MRUQgQ2lyY2xlIChZZWxsb3cpPC9k
Yzp0aXRsZT4KICAgICAgICA8ZGM6ZGVzY3JpcHRpb24+amVhbi52aWN0b3IuYmFsaW5AZ21haWwu
Y29tPC9kYzpkZXNjcmlwdGlvbj4KICAgICAgICA8ZGM6c3ViamVjdD4KICAgICAgICAgIDxyZGY6
QmFnPgogICAgICAgICAgICA8cmRmOmxpPmxlZDwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxp
PnNoYXBlPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0
PgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQgcmRmOmFib3V0PSJo
dHRwOi8vd3d3Lm9wZW5jbGlwYXJ0Lm9yZy8iPgogICAgICAgICAgICA8ZGM6dGl0bGU+T3BlbiBD
bGlwIEFydCBMaWJyYXJ5PC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAg
PC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+
CiAgICAgICAgICAgIDxkYzp0aXRsZT5KZWFuLVZpY3RvciBCYWxpbjwvZGM6dGl0bGU+CiAgICAg
ICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRz
PgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+SmVhbi1WaWN0b3Ig
QmFsaW48L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0
cz4KICAgICAgICA8ZGM6ZGF0ZT4yMDA1LTA4LTIxPC9kYzpkYXRlPgogICAgICAgIDxkYzpmb3Jt
YXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlIHJkZjpyZXNvdXJj
ZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiLz4KICAgICAgICA8Y2M6
bGljZW5zZSByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL1B1YmxpY0Rv
bWFpbiIvPgogICAgICAgIDxkYzpsYW5ndWFnZT5lbjwvZGM6bGFuZ3VhZ2U+CiAgICAgIDwvY2M6
V29yaz4KICAgICAgPGNjOkxpY2Vuc2UgcmRmOmFib3V0PSJodHRwOi8vd2ViLnJlc291cmNlLm9y
Zy9jYy9QdWJsaWNEb21haW4iPgogICAgICAgIDxjYzpwZXJtaXRzIHJkZjpyZXNvdXJjZT0iaHR0
cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvUmVwcm9kdWN0aW9uIi8+CiAgICAgICAgPGNjOnBlcm1p
dHMgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9EaXN0cmlidXRpb24i
Lz4KICAgICAgICA8Y2M6cGVybWl0cyByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uu
b3JnL2NjL0Rlcml2YXRpdmVXb3JrcyIvPgogICAgICA8L2NjOkxpY2Vuc2U+CiAgICA8L3JkZjpS
REY+CiAgPC9tZXRhZGF0YT4KICA8ZGVmcyBpZD0iZGVmczk0OTUiPgogICAgPGxpbmVhckdyYWRp
ZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQ3NTM0
IiBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIHgxPSIyMy40MDI1NjUiIHgyPSIyMy4zODk4NzQi
IHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDY1MDYiIHkxPSI0NC4wNjY3NzYiIHkyPSI0Mi44
ODM2OTgiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyR3JhZGllbnQ3NTAwIj4KICAg
ICAgPHN0b3AgaWQ9InN0b3A3NTAyIiBvZmZzZXQ9IjAuMDAwMDAwMCIgc3R5bGU9InN0b3AtY29s
b3I6I2QyY2QwMDtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIvPgogICAgICA8c3RvcCBpZD0ic3Rv
cDc1MDQiIG9mZnNldD0iMS4wMDAwMDAwIiBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZThmO3N0b3At
b3BhY2l0eToxLjAwMDAwMDA7Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdy
YWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQ3
NTMyIiBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIHgxPSIyMy4yMTM5ODAiIHgyPSIyMy4yMDEy
OTAiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDc1MDAiIHkxPSI0Mi43NTQ2MzEiIHkyPSI0
My44OTI2MzIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VP
blVzZSIgaWQ9ImxpbmVhckdyYWRpZW50NzUzMCIgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiB4
MT0iMjMuMzQ5Njk1IiB4Mj0iMjMuNDQwNTgwIiB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1
NzU2IiB5MT0iNDIuNzY3OTQ0IiB5Mj0iNDMuNzEwODczIi8+CiAgICA8bGluZWFyR3JhZGllbnQg
Z3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDc1MjgiIGlu
a3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgeDE9IjIzLjE5MzEwMiIgeDI9IjIzLjIwMDAwMSIgeGxp
bms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTc0MiIgeTE9IjQyLjQyOTIzMCIgeTI9IjQ0LjAwMDAw
MCIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXJHcmFkaWVudDY1MDYiPgogICAgICA8
c3RvcCBpZD0ic3RvcDY1MDgiIG9mZnNldD0iMC4wMDAwMDAwIiBzdHlsZT0ic3RvcC1jb2xvcjoj
ZmZmZmZmO3N0b3Atb3BhY2l0eTowLjAwMDAwMDA7Ii8+CiAgICAgIDxzdG9wIGlkPSJzdG9wNjUx
MCIgb2Zmc2V0PSIxLjAwMDAwMDAiIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFj
aXR5OjAuODc0NTA5ODE7Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRp
ZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQ3NDk4
IiBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIHgxPSIyMy40MDI1NjUiIHgyPSIyMy4zODk4NzQi
IHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDY1MDYiIHkxPSI0NC4wNjY3NzYiIHkyPSI0Mi44
ODM2OTgiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyR3JhZGllbnQ3NDY0Ij4KICAg
ICAgPHN0b3AgaWQ9InN0b3A3NDY2IiBvZmZzZXQ9IjAuMDAwMDAwMCIgc3R5bGU9InN0b3AtY29s
b3I6IzAwMDM5YTtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIvPgogICAgICA8c3RvcCBpZD0ic3Rv
cDc0NjgiIG9mZnNldD0iMS4wMDAwMDAwIiBzdHlsZT0ic3RvcC1jb2xvcjojYWZhNWZmO3N0b3At
b3BhY2l0eToxLjAwMDAwMDA7Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdy
YWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQ3
NDk2IiBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIHgxPSIyMy4yMTM5ODAiIHgyPSIyMy4yMDEy
OTAiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDc0NjQiIHkxPSI0Mi43NTQ2MzEiIHkyPSI0
My44OTI2MzIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyR3JhZGllbnQ1NzU2Ij4K
ICAgICAgPHN0b3AgaWQ9InN0b3A1NzU4IiBvZmZzZXQ9IjAuMDAwMDAwMCIgc3R5bGU9InN0b3At
Y29sb3I6IzgyODI4MjtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIvPgogICAgICA8c3RvcCBpZD0i
c3RvcDU3NjAiIG9mZnNldD0iMS4wMDAwMDAwIiBzdHlsZT0ic3RvcC1jb2xvcjojOTI5MjkyO3N0
b3Atb3BhY2l0eTowLjM1Mjk0MTE5OyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5l
YXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9ImxpbmVhckdyYWRp
ZW50OTMyMSIgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiB4MT0iMjIuOTM1MDMwIiB4Mj0iMjMu
NjYyMTA2IiB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1NzU2IiB5MT0iNDIuNjk5Nzc2IiB5
Mj0iNDMuODkyNjMyIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50NTc0
MiI+CiAgICAgIDxzdG9wIGlkPSJzdG9wNTc0NCIgb2Zmc2V0PSIwLjAwMDAwMDAiIHN0eWxlPSJz
dG9wLWNvbG9yOiNhZGFkYWQ7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiLz4KICAgICAgPHN0b3Ag
aWQ9InN0b3A1NzQ2IiBvZmZzZXQ9IjEuMDAwMDAwMCIgc3R5bGU9InN0b3AtY29sb3I6I2YwZjBm
MDtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxs
aW5lYXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9ImxpbmVhckdy
YWRpZW50NzQ5MiIgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiB4MT0iMjMuMTkzMTAyIiB4Mj0i
MjMuMjAwMDAxIiB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1NzQyIiB5MT0iNDIuNDI5MjMw
IiB5Mj0iNDQuMDAwMDAwIi8+CiAgICA8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRVbml0cz0idXNl
clNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDk1MjciIGlua3NjYXBlOmNvbGxlY3Q9ImFs
d2F5cyIgeDE9IjIzLjE5MzEwMiIgeDI9IjIzLjIwMDAwMSIgeGxpbms6aHJlZj0iI2xpbmVhckdy
YWRpZW50NTc0MiIgeTE9IjQyLjQyOTIzMCIgeTI9IjQ0LjAwMDAwMCIvPgogICAgPGxpbmVhckdy
YWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQ5
NTI5IiBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIHgxPSIyMi45MzUwMzAiIHgyPSIyMy42NjIx
MDYiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDU3NTYiIHkxPSI0Mi42OTk3NzYiIHkyPSI0
My44OTI2MzIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VP
blVzZSIgaWQ9ImxpbmVhckdyYWRpZW50OTUzMSIgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiB4
MT0iMjMuMjEzOTgwIiB4Mj0iMjMuMjAxMjkwIiB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ3
NDY0IiB5MT0iNDIuNzU0NjMxIiB5Mj0iNDMuODkyNjMyIi8+CiAgICA8bGluZWFyR3JhZGllbnQg
Z3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDk1MzMiIGlu
a3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgeDE9IjIzLjQwMjU2NSIgeDI9IjIzLjM4OTg3NCIgeGxp
bms6aHJlZj0iI2xpbmVhckdyYWRpZW50NjUwNiIgeTE9IjQ0LjA2Njc3NiIgeTI9IjQyLjg4MzY5
OCIvPgogICAgPGxpbmVhckdyYWRpZW50IGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMjQuMTYy
MzgsMC4wMDAwMDAsMC4wMDAwMDAsMTguNjg1NTYsLTUzOC4yNDY0LC03OTAuMDM4NykiIGdyYWRp
ZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQxMzM2IiBpbmtzY2Fw
ZTpjb2xsZWN0PSJhbHdheXMiIHgxPSIyMy40MTA0NjMiIHgyPSIyMy4zOTM4MjIiIHhsaW5rOmhy
ZWY9IiNsaW5lYXJHcmFkaWVudDY1MDYiIHkxPSI0NC40ODU1MTYiIHkyPSI0My4wMjY2ODQiLz4K
ICAgIDxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDMwLjI4MzUwLDAu
MDAwMDAwLDAuMDAwMDAwLDMwLjI4MzUwLC02ODAuOTA2MiwtMTI4Ni4xNjEpIiBncmFkaWVudFVu
aXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9ImxpbmVhckdyYWRpZW50MTMzOSIgaW5rc2NhcGU6Y29s
bGVjdD0iYWx3YXlzIiB4MT0iMjMuMjEzOTgwIiB4Mj0iMjMuMjAxMjkwIiB4bGluazpocmVmPSIj
bGluZWFyR3JhZGllbnQ3NTAwIiB5MT0iNDIuNzU0NjMxIiB5Mj0iNDMuODkyNjMyIi8+CiAgICA8
bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgzMy44MjczMSwwLjAwMDAw
MCwwLjAwMDAwMCwzMy44MjczMSwtNzYzLjUxMjIsLTE0MzkuNTk0KSIgZ3JhZGllbnRVbml0cz0i
dXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDEzNDIiIGlua3NjYXBlOmNvbGxlY3Q9
ImFsd2F5cyIgeDE9IjIzLjM0OTY5NSIgeDI9IjIzLjQ0MDU4MCIgeGxpbms6aHJlZj0iI2xpbmVh
ckdyYWRpZW50NTc1NiIgeTE9IjQyLjc2Nzk0NCIgeTI9IjQzLjcxMDg3MyIvPgogICAgPGxpbmVh
ckdyYWRpZW50IGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMzEuMjUwMDAsMC4wMDAwMDAsMC4w
MDAwMDAsMzEuMjUwMDAsLTcwMC4wMDAwLC0xMzI1LjAwMCkiIGdyYWRpZW50VW5pdHM9InVzZXJT
cGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQxMzQ1IiBpbmtzY2FwZTpjb2xsZWN0PSJhbHdh
eXMiIHgxPSIyMy4xOTMxMDIiIHgyPSIyMy4yMDAwMDEiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFk
aWVudDU3NDIiIHkxPSI0Mi40MjkyMzAiIHkyPSI0NC4wMDAwMDAiLz4KICA8L2RlZnM+CiAgPHNv
ZGlwb2RpOm5hbWVkdmlldyBib3JkZXJjb2xvcj0iIzY2NjY2NiIgYm9yZGVyb3BhY2l0eT0iMS4w
IiBpZD0iYmFzZSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIiBpbmtzY2FwZTpjeD0i
MjUuMDAwMDAwIiBpbmtzY2FwZTpjeT0iMjUuMDAwMDAwIiBpbmtzY2FwZTpkb2N1bWVudC11bml0
cz0icHgiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIi
IGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjY5MyIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxMDI0
IiBpbmtzY2FwZTp3aW5kb3cteD0iMCIgaW5rc2NhcGU6d2luZG93LXk9IjI1IiBpbmtzY2FwZTp6
b29tPSIxMC40ODAwMDAiIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIvPgogIDxnIGlkPSJsYXllcjEiIGlu
a3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiIGlua3NjYXBlOmxhYmVsPSJDYWxxdWUgMSI+CiAgICA8
ZyBpZD0iZzEzNDciPgogICAgICA8cGF0aCBkPSJNIDUwLjAwMDAzMSwyNS4wMDAwMzEgQyA1MC4w
MDAwMzEsMzguODAwMDMxIDM4LjgwMDAzMSw1MC4wMDAwMzEgMjUuMDAwMDMxLDUwLjAwMDAzMSBD
IDExLjIwMDAzMSw1MC4wMDAwMzEgMy4xMjUwMDAwZS0wNSwzOC44MDAwMzEgMy4xMjUwMDAwZS0w
NSwyNS4wMDAwMzEgQyAzLjEyNTAwMDBlLTA1LDExLjIwMDAzMSAxMS4yMDAwMzEsMy4xMjUwMDAw
ZS0wNSAyNS4wMDAwMzEsMy4xMjUwMDAwZS0wNSBDIDM4LjgwMDAzMSwzLjEyNTAwMDBlLTA1IDUw
LjAwMDAzMSwxMS4yMDAwMzEgNTAuMDAwMDMxLDI1LjAwMDAzMSB6ICIgaWQ9InBhdGg3NTA2IiBz
dHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MTM0NSk7ZmlsbC1vcGFjaXR5OjEuMDAwMDAw
MDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC44MDAwMDAwMTtzdHJva2UtbGluZWNhcDpyb3Vu
ZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NC4wMDAwMDAwO3N0cm9r
ZS1vcGFjaXR5OjEuMDAwMDAwMDtvdmVyZmxvdzp2aXNpYmxlIi8+CiAgICAgIDxwYXRoIGQ9Ik0g
NDUuMTc1NTgzLDI1LjAwMDExNSBDIDQ1LjE3NTU4MywzNi4xMzcwNDYgMzYuMTM2OTI2LDQ1LjE3
NTcwMyAyNC45OTk5OTQsNDUuMTc1NzAzIEMgMTMuODYzMDYzLDQ1LjE3NTcwMyA0LjgyNDQwNTcs
MzYuMTM3MDQ2IDQuODI0NDA1NywyNS4wMDAxMTUgQyA0LjgyNDQwNTcsMTMuODYzMTgzIDEzLjg2
MzA2Myw0LjgyNDQ5MjAgMjQuOTk5OTk0LDQuODI0NDkyMCBDIDM2LjEzNjkyNiw0LjgyNDQ5MjAg
NDUuMTc1NTgzLDEzLjg2MzE4MyA0NS4xNzU1ODMsMjUuMDAwMTE1IHogIiBpZD0icGF0aDc1MDgi
IHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQxMzQyKTtmaWxsLW9wYWNpdHk6MS4wMDAw
MDAwO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjgwMDAwMDAxO3N0cm9rZS1saW5lY2FwOnJv
dW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0LjAwMDAwMDA7c3Ry
b2tlLW9wYWNpdHk6MS4wMDAwMDAwO292ZXJmbG93OnZpc2libGUiLz4KICAgICAgPHBhdGggZD0i
TSA0My4wNjE5OTIsMjQuOTk5NTk0IEMgNDMuMDYxOTkyLDM0Ljk2OTgwMCAzNC45NzAyNDEsNDMu
MDYxNTUxIDI1LjAwMDAzNSw0My4wNjE1NTEgQyAxNS4wMjk4MjgsNDMuMDYxNTUxIDYuOTM4MDc3
MiwzNC45Njk4MDAgNi45MzgwNzcyLDI0Ljk5OTU5NCBDIDYuOTM4MDc3MiwxNS4wMjkzODcgMTUu
MDI5ODI4LDYuOTM3NjA1OSAyNS4wMDAwMzUsNi45Mzc2MDU5IEMgMzQuOTcwMjQxLDYuOTM3NjA1
OSA0My4wNjE5OTIsMTUuMDI5Mzg3IDQzLjA2MTk5MiwyNC45OTk1OTQgeiAiIGlkPSJwYXRoNzUx
MCIgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDEzMzkpO2ZpbGwtb3BhY2l0eToxLjAw
MDAwMDA7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuODAwMDAwMDE7c3Ryb2tlLWxpbmVjYXA6
cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQuMDAwMDAwMDtz
dHJva2Utb3BhY2l0eToxLjAwMDAwMDA7b3ZlcmZsb3c6dmlzaWJsZSIvPgogICAgICA8cGF0aCBk
PSJNIDM5LjM4ODEwNiwxOC45NzUxMTggQyAzOS4zODgxMDYsMjUuMTI2OTQ2IDMyLjkzMTkxOCwz
MC4xMTk3MjcgMjQuOTc2OTYyLDMwLjExOTcyNyBDIDE3LjAyMjAwNiwzMC4xMTk3MjcgMTAuNTY1
ODE4LDI1LjEyNjk0NiAxMC41NjU4MTgsMTguOTc1MTE4IEMgMTAuNTY1ODE4LDEyLjgyMzI4OSAx
Ny4wMjIwMDYsNy44MzA0ODkxIDI0Ljk3Njk2Miw3LjgzMDQ4OTEgQyAzMi45MzE5MTgsNy44MzA0
ODkxIDM5LjM4ODEwNiwxMi44MjMyODkgMzkuMzg4MTA2LDE4Ljk3NTExOCB6ICIgaWQ9InBhdGg3
NTEyIiBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MTMzNik7ZmlsbC1vcGFjaXR5OjEu
MDAwMDAwMDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC44MDAwMDAwMTtzdHJva2UtbGluZWNh
cDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NC4wMDAwMDAw
O3N0cm9rZS1vcGFjaXR5OjEuMDAwMDAwMDtvdmVyZmxvdzp2aXNpYmxlIi8+CiAgICA8L2c+CiAg
PC9nPgo8L3N2Zz4K
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010 Eduardo Aguiar
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import os.path
import os
import urllib
import fcntl
import struct
import ctypes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief constants
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
STATUS_GOOD, STATUS_BAD, STATUS_UNKNOWN = range (3)
SG_DXFER_FROM_DEV = -3 # <scsi/sg.h>
SG_IO = 0x2285 # <scsi/sg.h>
SG_INFO_OK_MASK = 0x01 # <scsi/sg.h>
SG_INFO_OK = 0x00 # <scsi/sg.h>
SCSI_INQUIRY = 0x12 # <scsi/scsi.h>
SCSI_READ_CAPACITY = 0x25 # <scsi/scsi.h>
VPD_SUPPORTED_VPDS = 0x00
VPD_UNIT_SERIAL_NUM = 0x80
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief SCSI Reader
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class Reader (object):
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief initialize reader
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def __init__ (self, datasource):
self.__uri = gdata.mediator.call ('object.get-attribute', datasource, 'uri')
self.__image_size = int (gdata.mediator.call ('object.get-attribute', datasource, 'size'))
self.__sector_size = int (gdata.mediator.call ('object.get-attribute', datasource, 'sector_size'))
self.__pos = 0
self.__stream = None
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief del reader
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def __del__ (self):
self.close ()
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @deprecated walk through all segment files
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def __iter__ (self):
data = self.read (self.__sector_size)
while data:
yield STATUS_UNKNOWN, data
data = self.read (self.__sector_size)
self.close ()
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief close reader
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def close (self):
if self.__stream:
self.__stream.close ()
self.__image_size = 0
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief set reading position
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def seek (self, pos, whence):
if whence == 0: # from beginning of file
abs_pos = pos
elif whence == 1: # from current position
abs_pos = self.__pos + pos
elif whence == 2: # from end of file
abs_pos = self.__image_size - 1 + pos
if abs_pos >= 0 and abs_pos < self.__image_size:
self.__pos = abs_pos
self.__stream = None
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief get the current reading position
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def tell (self):
return self.__pos
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief read bytes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def read (self, siz):
if not self.__stream:
path = urllib.unquote (self.__uri)[7:]
self.__stream = open (path)
self.__stream.seek (self.__pos, 0)
data = self.__stream.read (siz)
self.__pos += len (data)
return data
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief SCSI datasource support
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class SCSIHandler (object):
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief initialize object
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def __init__ (self):
object.__init__ (self)
self.type = 'scsi'
self.description = 'SCSI device'
self.extensions = []
self.Reader = Reader
self.default_item_category = 'harddisk'
self.is_exportable = False
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief verify if it is a linux device
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def signature_found (self, uri):
path = urllib.unquote(uri)[7:]
statinfo = os.stat(path)
if (((statinfo.st_mode & 0x06000) == 0x6000) and # it is a block device
(os.major(statinfo.st_rdev) == 8) and # SCSI disk device type
((os.minor(statinfo.st_rdev) & 0x0f) == 0)): # it not a partition
return True
return False
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief retrieve metadata from uri
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def retrieve_metadata (self, uri):
path = urllib.unquote(uri)[7:]
metadata = {}
metadata['type'] = 'scsi'
metadata['uri'] = uri
metadata['name'] = os.path.basename(path) # device name
fd = os.open(path, os.O_RDONLY)
# SCSI inquiry
cdb = ctypes.create_string_buffer(6)
sense = ctypes.create_string_buffer(32)
buf = ctypes.create_string_buffer(128)
io = struct.pack('@iiBB2xIPPPI8xP20x', ord('S'), SG_DXFER_FROM_DEV,
len(cdb), len(sense), len(buf), ctypes.addressof(buf),
ctypes.addressof(cdb), ctypes.addressof(sense), 10000, 0)
sg_io = ctypes.create_string_buffer(len(io))
sg_io = io
cdb[0] = chr(SCSI_INQUIRY)
if fcntl.ioctl(fd, SG_IO, sg_io) >= 0:
if (struct.unpack('@I', sg_io[-4:])[0] & SG_INFO_OK_MASK) == SG_INFO_OK:
metadata['drive_vendor'] = buf[8:16].strip()
metadata['drive_model'] = buf[16:32].strip()
metadata['drive_firmware'] = buf[32:36].strip()
cdb[1] = chr(0x01) # read vital product data
cdb[2] = chr(VPD_SUPPORTED_VPDS) # supported vpd's page code
if fcntl.ioctl(fd, SG_IO, sg_io) >= 0:
if (struct.unpack('@I', sg_io[-4:])[0] & SG_INFO_OK_MASK) == SG_INFO_OK:
if chr(VPD_UNIT_SERIAL_NUM) in buf[4:(4 + ord(buf[3]))]:
cdb[2] = chr(VPD_UNIT_SERIAL_NUM) # unit serial number page code
if fcntl.ioctl(fd, SG_IO, sg_io) >= 0:
if (struct.unpack('@I', sg_io[-4:])[0] & SG_INFO_OK_MASK) == SG_INFO_OK:
metadata['drive_serial'] = buf[4:(4 + ord(buf[3]))].strip()
# SCSI read capacity (10)
cdb = ctypes.create_string_buffer(10)
sense = ctypes.create_string_buffer(32)
buf = ctypes.create_string_buffer(128)
io = struct.pack('@iiBB2xIPPPI8xP20x', ord('S'), SG_DXFER_FROM_DEV,
len(cdb), len(sense), len(buf), ctypes.addressof(buf),
ctypes.addressof(cdb), ctypes.addressof(sense), 10000, 0)
sg_io = ctypes.create_string_buffer(len(io))
sg_io = io
cdb[0] = chr(SCSI_READ_CAPACITY)
if fcntl.ioctl(fd, SG_IO, sg_io) >= 0:
if (struct.unpack('@I', sg_io[-4:])[0] & SG_INFO_OK_MASK) == SG_INFO_OK:
last_lba, block_len = struct.unpack('>II', buf[:8])
if last_lba < 0xffffffff:
last_lba = last_lba + 1
metadata['total_sectors'] = last_lba
metadata['sector_size'] = block_len
metadata['size'] = last_lba * block_len
os.close(fd)
return metadata
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief set item attributes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def set_item_attributes (self, item, datasource):
category = gdata.mediator.call ('item.get-attribute', item, 'category')
if category != 'harddisk':
return
drive_vendor = gdata.mediator.call ('object.get-attribute', datasource, 'drive_vendor')
part_id = gdata.mediator.call ('object.get-attribute', datasource, 'drive_model')
drive_serial = gdata.mediator.call ('object.get-attribute', datasource, 'drive_serial')
drive_firmware = gdata.mediator.call ('object.get-attribute', datasource, 'drive_firmware')
size = gdata.mediator.call ('object.get-attribute', datasource, 'size')
total_sectors = gdata.mediator.call ('object.get-attribute', datasource, 'total_sectors')
sector_size = gdata.mediator.call ('object.get-attribute', datasource, 'sector_size')
gdata.mediator.call ('item.set-attribute', item, 'vendor', drive_vendor)
gdata.mediator.call ('item.set-attribute', item, 'part_id', part_id)
gdata.mediator.call ('item.set-attribute', item, 'serial', drive_serial)
gdata.mediator.call ('item.set-attribute', item, 'firmware', drive_firmware)
gdata.mediator.call ('item.set-attribute', item, 'lba', total_sectors)
gdata.mediator.call ('item.set-attribute', item, 'sector_size', sector_size)
gdata.mediator.call ('item.set-attribute', item, 'real_capacity', size)
gdata.mediator.call ('item.expand-value-masks', item)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief start function
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def pvt_start ():
gdata.mediator.call ('datasource.add-handler', SCSIHandler ())
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief stop function
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def pvt_stop ():
gdata.mediator.call ('datasource.remove-handler', 'scsi')