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')