#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 1.0.4 on Tue Apr 25 11:49:17 2023
#
import wx
# begin wxGlade: dependencies
# end wxGlade
# begin wxGlade: extracode
from pubsub import pub
from simple_database import Env, install_package, interp
import sys
class Controller(object):
def __init__(self):
pub.subscribe(self.read, "Controller")
self.table = {"OnNewFile": "new_file",
"OnOpen": "open_file",
"OnSaveFile": "save_file",
"OnSaveFileAs": "save_file_as",
"OnQuit": "quit",
"OnAddCD": "insert_value",
"Delete": "delete"}
def read(self, x, env):
pub.sendMessage("Model.eval",
x = [self.table[x[0]]] + x[1:],
env = env)
class Model(object):
def __init__(self):
pub.subscribe(self.eval, "Model")
def eval(self, x, env):
pub.sendMessage("View.SetProperties", env = interp(x, env))
def OnNewFile(self):
with NewFile(self) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
pub.sendMessage("Controller.read",
x = ["OnNewFile", fileDialog.GetPath()],
env = self.env)
def OnOpen(self):
with OpenFile(self) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
pub.sendMessage("Controller.read",
x = ["OnOpen", fileDialog.GetPath()],
env = self.env)
def OnSaveFileAs(self):
with SaveFileAs(self) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
pub.sendMessage("Controller.read",
x = ["OnSaveFileAs", fileDialog.GetPath()],
env = self.env)
# end wxGlade
class View(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: View.__init__
self.env = Env(install_package())
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((400, 300))
self.SetTitle("Simple Database")
# Menu Bar
self.frame_menubar = wx.MenuBar()
wxglade_tmp_menu = wx.Menu()
item = wxglade_tmp_menu.Append(wx.ID_ANY, u"新規作成\tCtrl+N", "")
self.Bind(wx.EVT_MENU, lambda event: OnNewFile(self), item)
item = wxglade_tmp_menu.Append(wx.ID_ANY, u"開く...\tCtrl+O", "")
self.Bind(wx.EVT_MENU, lambda event: OnOpen(self), item)
item = wxglade_tmp_menu.Append(wx.ID_ANY, u"保存\tCtrl+S", "")
self.Bind(wx.EVT_MENU, lambda event: pub.sendMessage('Controller.read', x = ['OnSaveFile'], env = self.env), item)
item = wxglade_tmp_menu.Append(wx.ID_ANY, u"名前を付けて保存...\tShift+Ctrl+S", "")
self.Bind(wx.EVT_MENU, lambda event: OnSaveAs(self), item)
item = wxglade_tmp_menu.Append(wx.ID_ANY, "Quit\tCtrl+Q", "")
self.Bind(wx.EVT_MENU, lambda event: pub.sendMessage('Controller.read', x = ['OnQuit'], env = self.env), item)
self.frame_menubar.Append(wxglade_tmp_menu, u"ファイル")
self.SetMenuBar(self.frame_menubar)
# Menu Bar end
sizer_1 = wx.BoxSizer(wx.VERTICAL)
self.AddCD = wx.Button(self, wx.ID_ANY, "AddCD")
sizer_1.Add(self.AddCD, 0, 0, 0)
self.list_ctrl_1 = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES)
self.list_ctrl_1.AppendColumn(u"タイトル", format=wx.LIST_FORMAT_LEFT, width=-1)
self.list_ctrl_1.AppendColumn(u"アーティスト", format=wx.LIST_FORMAT_LEFT, width=-1)
self.list_ctrl_1.AppendColumn(u"レーティング", format=wx.LIST_FORMAT_LEFT, width=-1)
self.list_ctrl_1.AppendColumn(u"リップ", format=wx.LIST_FORMAT_LEFT, width=-1)
sizer_1.Add(self.list_ctrl_1, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
pub.subscribe(self.SetProperties, 'View')
self.Bind(wx.EVT_BUTTON, lambda event: AddCDDialog(self).ShowModal(), self.AddCD)
self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.rclick, self.list_ctrl_1)
# end wxGlade
# SetProperies メソッドを追加
def SetProperties(self, env):
self.env = env
self.list_ctrl_1.DeleteAllItems() # ここで一旦表示を全消去する
[[self.list_ctrl_1.InsertItem(sys.maxsize, obj) if col == 0
else self.list_ctrl_1.SetItem(index, col, obj) for col, obj
in enumerate([item.title, item.artist, item.rating, item.ripped])]
for index, item in enumerate(self.env.ls)]
def rclick(self, event): # wxGlade: View.<event_handler>
## print("Event handler 'rclick' not implemented!")
## event.Skip()
## 上の自動生成部分二行をコメントアウトして以下を追加する
menu_file = wx.Menu() # メニューを定義
item = wx.MenuItem(menu_file, 1, '削除') # メニューの選択肢を定義
menu_file.Append(item) # 選択肢をメニューに仕込む
menu_file.Bind(wx.EVT_MENU, self.menu_select) # メニューのイベントハンドラとして menu_select を使用
wx.Window.PopupMenu(self, menu_file, event.GetPoint()) # ポップアップを生成
# menu_select メソッドを追加
def menu_select(self, event):
id = event.GetId() # 選択肢番号を取得
if id == 1:
pub.sendMessage('Controller.read',
x = ['Delete',
str(self.list_ctrl_1.GetFocusedItem())],
env = self.env)
# end of class View
class AddCDDialog(wx.Dialog):
def __init__(self, *args, **kwds):
# begin wxGlade: AddCDDialog.__init__
self.env = args[0].env
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE
wx.Dialog.__init__(self, *args, **kwds)
self.SetTitle("Add CD")
sizer_1 = wx.BoxSizer(wx.VERTICAL)
grid_sizer_1 = wx.GridSizer(4, 2, 0, 0)
sizer_1.Add(grid_sizer_1, 1, wx.EXPAND, 0)
Title = wx.StaticText(self, wx.ID_ANY, u"タイトル")
grid_sizer_1.Add(Title, 0, wx.ALIGN_CENTER, 0)
self.text_ctrl_1 = wx.TextCtrl(self, wx.ID_ANY, "")
grid_sizer_1.Add(self.text_ctrl_1, 0, wx.ALIGN_CENTER, 0)
Artist = wx.StaticText(self, wx.ID_ANY, u"アーティスト")
grid_sizer_1.Add(Artist, 0, wx.ALIGN_CENTER, 0)
self.text_ctrl_2 = wx.TextCtrl(self, wx.ID_ANY, "")
grid_sizer_1.Add(self.text_ctrl_2, 0, wx.ALIGN_CENTER, 0)
Rating = wx.StaticText(self, wx.ID_ANY, u"レーティング")
grid_sizer_1.Add(Rating, 0, wx.ALIGN_CENTER, 0)
self.text_ctrl_3 = wx.TextCtrl(self, wx.ID_ANY, "")
grid_sizer_1.Add(self.text_ctrl_3, 0, wx.ALIGN_CENTER, 0)
Ripped = wx.StaticText(self, wx.ID_ANY, u"リップ")
grid_sizer_1.Add(Ripped, 0, wx.ALIGN_CENTER, 0)
self.text_ctrl_4 = wx.TextCtrl(self, wx.ID_ANY, "")
grid_sizer_1.Add(self.text_ctrl_4, 0, wx.ALIGN_CENTER, 0)
sizer_2 = wx.StdDialogButtonSizer()
sizer_1.Add(sizer_2, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
self.button_OK = wx.Button(self, wx.ID_OK, "")
self.button_OK.SetDefault()
sizer_2.AddButton(self.button_OK)
self.button_CANCEL = wx.Button(self, wx.ID_CANCEL, "")
sizer_2.AddButton(self.button_CANCEL)
sizer_2.Realize()
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.SetAffirmativeId(self.button_OK.GetId())
self.SetEscapeId(self.button_CANCEL.GetId())
self.Layout()
self.Bind(wx.EVT_BUTTON, lambda event: self.OnAddCD(), self.button_OK)
self.Bind(wx.EVT_BUTTON, lambda event: self.Destroy(), self.button_CANCEL)
# end wxGlade
# OnAddCD メソッドを追加
def OnAddCD(self):
pub.sendMessage('Controller.read',
x = ['OnAddCD',
self.text_ctrl_1.GetLineText(0),
self.text_ctrl_2.GetLineText(0),
self.text_ctrl_3.GetLineText(0),
self.text_ctrl_4.GetLineText(0)],
env = self.env)
self.Destroy()
# end of class AddCDDialog
##class NewFile(wx.Dialog): ここを修正
class NewFile(wx.FileDialog):
def __init__(self, *args, **kwds):
# begin wxGlade: NewFile.__init__
self.env = args[0].env
## 次の二行を修正
## kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE
## wx.Dialog.__init__(self, *args, **kwds)
kwds["style"] = kwds.get("style", 0) | wx.FD_SAVE
wx.FileDialog.__init__(self, *args, **kwds)
self.SetTitle(u"新規作成")
self.Layout()
# end wxGlade
# end of class NewFile
##class OpenFile(wx.Dialog): ここを修正
class OpenFile(wx.FileDialog):
def __init__(self, *args, **kwds):
# begin wxGlade: OpenFile.__init__
self.env = args[0].env
## 次の二行を修正
## kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE
## wx.Dialog.__init__(self, *args, **kwds)
kwds["style"] = kwds.get("style", 0) | wx.FD_OPEN
wx.FileDialog.__init__(self, *args, **kwds)
self.SetTitle(u"開く...")
self.Layout()
# end wxGlade
# end of class OpenFile
##class SaveFileAs(wx.Dialog): ここを修正
class SaveFileAs(wx.FileDialog):
def __init__(self, *args, **kwds):
# begin wxGlade: SaveFileAs.__init__
self.env = args[0].env
## 次の二行を修正
## kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE
## wx.Dialog.__init__(self, *args, **kwds)
kwds["style"] = kwds.get("style", 0) | wx.FD_SAVE
wx.FileDialog.__init__(self, *args, **kwds)
self.SetTitle(u"名前を付けて保存...")
self.Layout()
# end wxGlade
# end of class SaveFileAs
class SimpleDatabase(wx.App):
def OnInit(self):
self.View = View(None, wx.ID_ANY, "")
self.SetTopWindow(self.View)
self.View.Show()
return True
# end of class SimpleDatabase
if __name__ == "__main__":
m = Model() # 追加: Model
SimpleDatabase = SimpleDatabase(0) # View
c = Controller() # 追加: Controller
SimpleDatabase.MainLoop()
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwojIC0qLSBjb2Rpbmc6IFVURi04IC0qLQojCiMgZ2VuZXJhdGVkIGJ5IHd4R2xhZGUgMS4wLjQgb24gVHVlIEFwciAyNSAxMTo0OToxNyAyMDIzCiMKCmltcG9ydCB3eAoKIyBiZWdpbiB3eEdsYWRlOiBkZXBlbmRlbmNpZXMKIyBlbmQgd3hHbGFkZQoKIyBiZWdpbiB3eEdsYWRlOiBleHRyYWNvZGUKZnJvbSBwdWJzdWIgaW1wb3J0IHB1Ygpmcm9tIHNpbXBsZV9kYXRhYmFzZSBpbXBvcnQgRW52LCBpbnN0YWxsX3BhY2thZ2UsIGludGVycAppbXBvcnQgc3lzCgpjbGFzcyBDb250cm9sbGVyKG9iamVjdCk6CiAgICBkZWYgX19pbml0X18oc2VsZik6CiAgICAgICAgcHViLnN1YnNjcmliZShzZWxmLnJlYWQsICJDb250cm9sbGVyIikKICAgICAgICBzZWxmLnRhYmxlID0geyJPbk5ld0ZpbGUiOiAibmV3X2ZpbGUiLAogICAgICAgICAgICAgICAgICAgICAgIk9uT3BlbiI6ICJvcGVuX2ZpbGUiLAogICAgICAgICAgICAgICAgICAgICAgIk9uU2F2ZUZpbGUiOiAic2F2ZV9maWxlIiwKICAgICAgICAgICAgICAgICAgICAgICJPblNhdmVGaWxlQXMiOiAic2F2ZV9maWxlX2FzIiwKICAgICAgICAgICAgICAgICAgICAgICJPblF1aXQiOiAicXVpdCIsCiAgICAgICAgICAgICAgICAgICAgICAiT25BZGRDRCI6ICJpbnNlcnRfdmFsdWUiLAogICAgICAgICAgICAgICAgICAgICAgIkRlbGV0ZSI6ICJkZWxldGUifQogICAgZGVmIHJlYWQoc2VsZiwgeCwgZW52KToKICAgICAgICBwdWIuc2VuZE1lc3NhZ2UoIk1vZGVsLmV2YWwiLAogICAgICAgICAgICAgICAgICAgICAgICB4ID0gW3NlbGYudGFibGVbeFswXV1dICsgeFsxOl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGVudiA9IGVudikKCmNsYXNzIE1vZGVsKG9iamVjdCk6CiAgICBkZWYgX19pbml0X18oc2VsZik6CiAgICAgICAgcHViLnN1YnNjcmliZShzZWxmLmV2YWwsICJNb2RlbCIpCiAgICBkZWYgZXZhbChzZWxmLCB4LCBlbnYpOgogICAgICAgIHB1Yi5zZW5kTWVzc2FnZSgiVmlldy5TZXRQcm9wZXJ0aWVzIiwgZW52ID0gaW50ZXJwKHgsIGVudikpCmRlZiBPbk5ld0ZpbGUoc2VsZik6CiAgICB3aXRoIE5ld0ZpbGUoc2VsZikgYXMgZmlsZURpYWxvZzoKICAgICAgICBpZiBmaWxlRGlhbG9nLlNob3dNb2RhbCgpID09IHd4LklEX0NBTkNFTDoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgcHViLnNlbmRNZXNzYWdlKCJDb250cm9sbGVyLnJlYWQiLAogICAgICAgICAgICAgICAgICAgICAgICB4ID0gWyJPbk5ld0ZpbGUiLCBmaWxlRGlhbG9nLkdldFBhdGgoKV0sCiAgICAgICAgICAgICAgICAgICAgICAgIGVudiA9IHNlbGYuZW52KQpkZWYgT25PcGVuKHNlbGYpOgogICAgd2l0aCBPcGVuRmlsZShzZWxmKSBhcyBmaWxlRGlhbG9nOgogICAgICAgIGlmIGZpbGVEaWFsb2cuU2hvd01vZGFsKCkgPT0gd3guSURfQ0FOQ0VMOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBwdWIuc2VuZE1lc3NhZ2UoIkNvbnRyb2xsZXIucmVhZCIsCiAgICAgICAgICAgICAgICAgICAgICAgIHggPSBbIk9uT3BlbiIsIGZpbGVEaWFsb2cuR2V0UGF0aCgpXSwKICAgICAgICAgICAgICAgICAgICAgICAgZW52ID0gc2VsZi5lbnYpCmRlZiBPblNhdmVGaWxlQXMoc2VsZik6CiAgICB3aXRoIFNhdmVGaWxlQXMoc2VsZikgYXMgZmlsZURpYWxvZzoKICAgICAgICBpZiBmaWxlRGlhbG9nLlNob3dNb2RhbCgpID09IHd4LklEX0NBTkNFTDoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgcHViLnNlbmRNZXNzYWdlKCJDb250cm9sbGVyLnJlYWQiLAogICAgICAgICAgICAgICAgICAgICAgICB4ID0gWyJPblNhdmVGaWxlQXMiLCBmaWxlRGlhbG9nLkdldFBhdGgoKV0sCiAgICAgICAgICAgICAgICAgICAgICAgIGVudiA9IHNlbGYuZW52KQojIGVuZCB3eEdsYWRlCgoKY2xhc3MgVmlldyh3eC5GcmFtZSk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgKmFyZ3MsICoqa3dkcyk6CiAgICAgICAgIyBiZWdpbiB3eEdsYWRlOiBWaWV3Ll9faW5pdF9fCiAgICAgICAgc2VsZi5lbnYgPSBFbnYoaW5zdGFsbF9wYWNrYWdlKCkpCiAgICAgICAga3dkc1sic3R5bGUiXSA9IGt3ZHMuZ2V0KCJzdHlsZSIsIDApIHwgd3guREVGQVVMVF9GUkFNRV9TVFlMRQogICAgICAgIHd4LkZyYW1lLl9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3ZHMpCiAgICAgICAgc2VsZi5TZXRTaXplKCg0MDAsIDMwMCkpCiAgICAgICAgc2VsZi5TZXRUaXRsZSgiU2ltcGxlIERhdGFiYXNlIikKCiAgICAgICAgIyBNZW51IEJhcgogICAgICAgIHNlbGYuZnJhbWVfbWVudWJhciA9IHd4Lk1lbnVCYXIoKQogICAgICAgIHd4Z2xhZGVfdG1wX21lbnUgPSB3eC5NZW51KCkKICAgICAgICBpdGVtID0gd3hnbGFkZV90bXBfbWVudS5BcHBlbmQod3guSURfQU5ZLCB1IuaWsOimj+S9nOaIkFx0Q3RybCtOIiwgIiIpCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9NRU5VLCBsYW1iZGEgZXZlbnQ6IE9uTmV3RmlsZShzZWxmKSwgaXRlbSkKICAgICAgICBpdGVtID0gd3hnbGFkZV90bXBfbWVudS5BcHBlbmQod3guSURfQU5ZLCB1IumWi+OBjy4uLlx0Q3RybCtPIiwgIiIpCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9NRU5VLCBsYW1iZGEgZXZlbnQ6IE9uT3BlbihzZWxmKSwgaXRlbSkKICAgICAgICBpdGVtID0gd3hnbGFkZV90bXBfbWVudS5BcHBlbmQod3guSURfQU5ZLCB1IuS/neWtmFx0Q3RybCtTIiwgIiIpCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9NRU5VLCBsYW1iZGEgZXZlbnQ6IHB1Yi5zZW5kTWVzc2FnZSgnQ29udHJvbGxlci5yZWFkJywgeCA9IFsnT25TYXZlRmlsZSddLCBlbnYgPSBzZWxmLmVudiksIGl0ZW0pCiAgICAgICAgaXRlbSA9IHd4Z2xhZGVfdG1wX21lbnUuQXBwZW5kKHd4LklEX0FOWSwgdSLlkI3liY3jgpLku5jjgZHjgabkv53lrZguLi5cdFNoaWZ0K0N0cmwrUyIsICIiKQogICAgICAgIHNlbGYuQmluZCh3eC5FVlRfTUVOVSwgbGFtYmRhIGV2ZW50OiBPblNhdmVBcyhzZWxmKSwgaXRlbSkKICAgICAgICBpdGVtID0gd3hnbGFkZV90bXBfbWVudS5BcHBlbmQod3guSURfQU5ZLCAiUXVpdFx0Q3RybCtRIiwgIiIpCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9NRU5VLCBsYW1iZGEgZXZlbnQ6IHB1Yi5zZW5kTWVzc2FnZSgnQ29udHJvbGxlci5yZWFkJywgeCA9IFsnT25RdWl0J10sIGVudiA9IHNlbGYuZW52KSwgaXRlbSkKICAgICAgICBzZWxmLmZyYW1lX21lbnViYXIuQXBwZW5kKHd4Z2xhZGVfdG1wX21lbnUsIHUi44OV44Kh44Kk44OrIikKICAgICAgICBzZWxmLlNldE1lbnVCYXIoc2VsZi5mcmFtZV9tZW51YmFyKQogICAgICAgICMgTWVudSBCYXIgZW5kCgogICAgICAgIHNpemVyXzEgPSB3eC5Cb3hTaXplcih3eC5WRVJUSUNBTCkKCiAgICAgICAgc2VsZi5BZGRDRCA9IHd4LkJ1dHRvbihzZWxmLCB3eC5JRF9BTlksICJBZGRDRCIpCiAgICAgICAgc2l6ZXJfMS5BZGQoc2VsZi5BZGRDRCwgMCwgMCwgMCkKCiAgICAgICAgc2VsZi5saXN0X2N0cmxfMSA9IHd4Lkxpc3RDdHJsKHNlbGYsIHd4LklEX0FOWSwgc3R5bGU9d3guTENfSFJVTEVTIHwgd3guTENfUkVQT1JUIHwgd3guTENfVlJVTEVTKQogICAgICAgIHNlbGYubGlzdF9jdHJsXzEuQXBwZW5kQ29sdW1uKHUi44K/44Kk44OI44OrIiwgZm9ybWF0PXd4LkxJU1RfRk9STUFUX0xFRlQsIHdpZHRoPS0xKQogICAgICAgIHNlbGYubGlzdF9jdHJsXzEuQXBwZW5kQ29sdW1uKHUi44Ki44O844OG44Kj44K544OIIiwgZm9ybWF0PXd4LkxJU1RfRk9STUFUX0xFRlQsIHdpZHRoPS0xKQogICAgICAgIHNlbGYubGlzdF9jdHJsXzEuQXBwZW5kQ29sdW1uKHUi44Os44O844OG44Kj44Oz44KwIiwgZm9ybWF0PXd4LkxJU1RfRk9STUFUX0xFRlQsIHdpZHRoPS0xKQogICAgICAgIHNlbGYubGlzdF9jdHJsXzEuQXBwZW5kQ29sdW1uKHUi44Oq44OD44OXIiwgZm9ybWF0PXd4LkxJU1RfRk9STUFUX0xFRlQsIHdpZHRoPS0xKQogICAgICAgIHNpemVyXzEuQWRkKHNlbGYubGlzdF9jdHJsXzEsIDEsIHd4LkVYUEFORCwgMCkKCiAgICAgICAgc2VsZi5TZXRTaXplcihzaXplcl8xKQoKICAgICAgICBzZWxmLkxheW91dCgpCiAgICAgICAgcHViLnN1YnNjcmliZShzZWxmLlNldFByb3BlcnRpZXMsICdWaWV3JykKCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9CVVRUT04sIGxhbWJkYSBldmVudDogQWRkQ0REaWFsb2coc2VsZikuU2hvd01vZGFsKCksIHNlbGYuQWRkQ0QpCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9MSVNUX0lURU1fUklHSFRfQ0xJQ0ssIHNlbGYucmNsaWNrLCBzZWxmLmxpc3RfY3RybF8xKQogICAgICAgICMgZW5kIHd4R2xhZGUKCiAgICAjIFNldFByb3BlcmllcyDjg6Hjgr3jg4Pjg4njgpLov73liqAKICAgIGRlZiBTZXRQcm9wZXJ0aWVzKHNlbGYsIGVudik6CiAgICAgICAgc2VsZi5lbnYgPSBlbnYKICAgICAgICBzZWxmLmxpc3RfY3RybF8xLkRlbGV0ZUFsbEl0ZW1zKCkgIyDjgZPjgZPjgafkuIDml6booajnpLrjgpLlhajmtojljrvjgZnjgosKICAgICAgICBbW3NlbGYubGlzdF9jdHJsXzEuSW5zZXJ0SXRlbShzeXMubWF4c2l6ZSwgb2JqKSBpZiBjb2wgPT0gMAogICAgICAgICAgZWxzZSBzZWxmLmxpc3RfY3RybF8xLlNldEl0ZW0oaW5kZXgsIGNvbCwgb2JqKSBmb3IgY29sLCBvYmoKICAgICAgICAgIGluIGVudW1lcmF0ZShbaXRlbS50aXRsZSwgaXRlbS5hcnRpc3QsIGl0ZW0ucmF0aW5nLCBpdGVtLnJpcHBlZF0pXQogICAgICAgICAgZm9yIGluZGV4LCBpdGVtIGluIGVudW1lcmF0ZShzZWxmLmVudi5scyldCiAgICAKICAgIGRlZiByY2xpY2soc2VsZiwgZXZlbnQpOiAgIyB3eEdsYWRlOiBWaWV3LjxldmVudF9oYW5kbGVyPgojIyAgICAgICAgcHJpbnQoIkV2ZW50IGhhbmRsZXIgJ3JjbGljaycgbm90IGltcGxlbWVudGVkISIpCiMjICAgICAgICBldmVudC5Ta2lwKCkKIyMgICAgICAgIOS4iuOBruiHquWLleeUn+aIkOmDqOWIhuS6jOihjOOCkuOCs+ODoeODs+ODiOOCouOCpuODiOOBl+OBpuS7peS4i+OCkui/veWKoOOBmeOCiwogICAgICAgIG1lbnVfZmlsZSA9IHd4Lk1lbnUoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIOODoeODi+ODpeODvOOCkuWumue+qQogICAgICAgIGl0ZW0gPSB3eC5NZW51SXRlbShtZW51X2ZpbGUsIDEsICfliYrpmaQnKSAgICAgICAgICAgICAgICMg44Oh44OL44Ol44O844Gu6YG45oqe6IKi44KS5a6a576pCiAgICAgICAgbWVudV9maWxlLkFwcGVuZChpdGVtKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMg6YG45oqe6IKi44KS44Oh44OL44Ol44O844Gr5LuV6L6844KACiAgICAgICAgbWVudV9maWxlLkJpbmQod3guRVZUX01FTlUsIHNlbGYubWVudV9zZWxlY3QpICAgICAgICAgICMg44Oh44OL44Ol44O844Gu44Kk44OZ44Oz44OI44OP44Oz44OJ44Op44Go44GX44GmIG1lbnVfc2VsZWN0IOOCkuS9v+eUqAogICAgICAgIHd4LldpbmRvdy5Qb3B1cE1lbnUoc2VsZiwgbWVudV9maWxlLCBldmVudC5HZXRQb2ludCgpKSAjIOODneODg+ODl+OCouODg+ODl+OCkueUn+aIkAoKICAgICMgbWVudV9zZWxlY3Qg44Oh44K944OD44OJ44KS6L+95YqgCiAgICBkZWYgbWVudV9zZWxlY3Qoc2VsZiwgZXZlbnQpOgogICAgICAgIGlkID0gZXZlbnQuR2V0SWQoKSAjIOmBuOaKnuiCoueVquWPt+OCkuWPluW+lwogICAgICAgIGlmIGlkID09IDE6CiAgICAgICAgICAgIHB1Yi5zZW5kTWVzc2FnZSgnQ29udHJvbGxlci5yZWFkJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBbJ0RlbGV0ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cihzZWxmLmxpc3RfY3RybF8xLkdldEZvY3VzZWRJdGVtKCkpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudiA9IHNlbGYuZW52KQoKIyBlbmQgb2YgY2xhc3MgVmlldwoKY2xhc3MgQWRkQ0REaWFsb2cod3guRGlhbG9nKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqYXJncywgKiprd2RzKToKICAgICAgICAjIGJlZ2luIHd4R2xhZGU6IEFkZENERGlhbG9nLl9faW5pdF9fCiAgICAgICAgc2VsZi5lbnYgPSBhcmdzWzBdLmVudgogICAgICAgIGt3ZHNbInN0eWxlIl0gPSBrd2RzLmdldCgic3R5bGUiLCAwKSB8IHd4LkRFRkFVTFRfRElBTE9HX1NUWUxFCiAgICAgICAgd3guRGlhbG9nLl9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3ZHMpCiAgICAgICAgc2VsZi5TZXRUaXRsZSgiQWRkIENEIikKCiAgICAgICAgc2l6ZXJfMSA9IHd4LkJveFNpemVyKHd4LlZFUlRJQ0FMKQoKICAgICAgICBncmlkX3NpemVyXzEgPSB3eC5HcmlkU2l6ZXIoNCwgMiwgMCwgMCkKICAgICAgICBzaXplcl8xLkFkZChncmlkX3NpemVyXzEsIDEsIHd4LkVYUEFORCwgMCkKCiAgICAgICAgVGl0bGUgPSB3eC5TdGF0aWNUZXh0KHNlbGYsIHd4LklEX0FOWSwgdSLjgr/jgqTjg4jjg6siKQogICAgICAgIGdyaWRfc2l6ZXJfMS5BZGQoVGl0bGUsIDAsIHd4LkFMSUdOX0NFTlRFUiwgMCkKCiAgICAgICAgc2VsZi50ZXh0X2N0cmxfMSA9IHd4LlRleHRDdHJsKHNlbGYsIHd4LklEX0FOWSwgIiIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChzZWxmLnRleHRfY3RybF8xLCAwLCB3eC5BTElHTl9DRU5URVIsIDApCgogICAgICAgIEFydGlzdCA9IHd4LlN0YXRpY1RleHQoc2VsZiwgd3guSURfQU5ZLCB1IuOCouODvOODhuOCo+OCueODiCIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChBcnRpc3QsIDAsIHd4LkFMSUdOX0NFTlRFUiwgMCkKCiAgICAgICAgc2VsZi50ZXh0X2N0cmxfMiA9IHd4LlRleHRDdHJsKHNlbGYsIHd4LklEX0FOWSwgIiIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChzZWxmLnRleHRfY3RybF8yLCAwLCB3eC5BTElHTl9DRU5URVIsIDApCgogICAgICAgIFJhdGluZyA9IHd4LlN0YXRpY1RleHQoc2VsZiwgd3guSURfQU5ZLCB1IuODrOODvOODhuOCo+ODs+OCsCIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChSYXRpbmcsIDAsIHd4LkFMSUdOX0NFTlRFUiwgMCkKCiAgICAgICAgc2VsZi50ZXh0X2N0cmxfMyA9IHd4LlRleHRDdHJsKHNlbGYsIHd4LklEX0FOWSwgIiIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChzZWxmLnRleHRfY3RybF8zLCAwLCB3eC5BTElHTl9DRU5URVIsIDApCgogICAgICAgIFJpcHBlZCA9IHd4LlN0YXRpY1RleHQoc2VsZiwgd3guSURfQU5ZLCB1IuODquODg+ODlyIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChSaXBwZWQsIDAsIHd4LkFMSUdOX0NFTlRFUiwgMCkKCiAgICAgICAgc2VsZi50ZXh0X2N0cmxfNCA9IHd4LlRleHRDdHJsKHNlbGYsIHd4LklEX0FOWSwgIiIpCiAgICAgICAgZ3JpZF9zaXplcl8xLkFkZChzZWxmLnRleHRfY3RybF80LCAwLCB3eC5BTElHTl9DRU5URVIsIDApCgogICAgICAgIHNpemVyXzIgPSB3eC5TdGREaWFsb2dCdXR0b25TaXplcigpCiAgICAgICAgc2l6ZXJfMS5BZGQoc2l6ZXJfMiwgMCwgd3guQUxJR05fUklHSFQgfCB3eC5BTEwsIDQpCgogICAgICAgIHNlbGYuYnV0dG9uX09LID0gd3guQnV0dG9uKHNlbGYsIHd4LklEX09LLCAiIikKICAgICAgICBzZWxmLmJ1dHRvbl9PSy5TZXREZWZhdWx0KCkKICAgICAgICBzaXplcl8yLkFkZEJ1dHRvbihzZWxmLmJ1dHRvbl9PSykKCiAgICAgICAgc2VsZi5idXR0b25fQ0FOQ0VMID0gd3guQnV0dG9uKHNlbGYsIHd4LklEX0NBTkNFTCwgIiIpCiAgICAgICAgc2l6ZXJfMi5BZGRCdXR0b24oc2VsZi5idXR0b25fQ0FOQ0VMKQoKICAgICAgICBzaXplcl8yLlJlYWxpemUoKQoKICAgICAgICBzZWxmLlNldFNpemVyKHNpemVyXzEpCiAgICAgICAgc2l6ZXJfMS5GaXQoc2VsZikKCiAgICAgICAgc2VsZi5TZXRBZmZpcm1hdGl2ZUlkKHNlbGYuYnV0dG9uX09LLkdldElkKCkpCiAgICAgICAgc2VsZi5TZXRFc2NhcGVJZChzZWxmLmJ1dHRvbl9DQU5DRUwuR2V0SWQoKSkKCiAgICAgICAgc2VsZi5MYXlvdXQoKQoKICAgICAgICBzZWxmLkJpbmQod3guRVZUX0JVVFRPTiwgbGFtYmRhIGV2ZW50OiBzZWxmLk9uQWRkQ0QoKSwgc2VsZi5idXR0b25fT0spCiAgICAgICAgc2VsZi5CaW5kKHd4LkVWVF9CVVRUT04sIGxhbWJkYSBldmVudDogc2VsZi5EZXN0cm95KCksIHNlbGYuYnV0dG9uX0NBTkNFTCkKICAgICAgICAjIGVuZCB3eEdsYWRlCgogICAgIyBPbkFkZENEIOODoeOCveODg+ODieOCkui/veWKoAogICAgZGVmIE9uQWRkQ0Qoc2VsZik6CiAgICAgICAgcHViLnNlbmRNZXNzYWdlKCdDb250cm9sbGVyLnJlYWQnLAogICAgICAgICAgICAgICAgICAgICAgICB4ID0gWydPbkFkZENEJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnRleHRfY3RybF8xLkdldExpbmVUZXh0KDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYudGV4dF9jdHJsXzIuR2V0TGluZVRleHQoMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi50ZXh0X2N0cmxfMy5HZXRMaW5lVGV4dCgwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnRleHRfY3RybF80LkdldExpbmVUZXh0KDApXSwKICAgICAgICAgICAgICAgICAgICAgICAgZW52ID0gc2VsZi5lbnYpCiAgICAgICAgc2VsZi5EZXN0cm95KCkKCiMgZW5kIG9mIGNsYXNzIEFkZENERGlhbG9nCgojI2NsYXNzIE5ld0ZpbGUod3guRGlhbG9nKTog44GT44GT44KS5L+u5q2jCmNsYXNzIE5ld0ZpbGUod3guRmlsZURpYWxvZyk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgKmFyZ3MsICoqa3dkcyk6CiAgICAgICAgIyBiZWdpbiB3eEdsYWRlOiBOZXdGaWxlLl9faW5pdF9fCiAgICAgICAgc2VsZi5lbnYgPSBhcmdzWzBdLmVudgojIyAgICAgICAg5qyh44Gu5LqM6KGM44KS5L+u5q2jCiMjICAgICAgICBrd2RzWyJzdHlsZSJdID0ga3dkcy5nZXQoInN0eWxlIiwgMCkgfCB3eC5ERUZBVUxUX0RJQUxPR19TVFlMRQojIyAgICAgICAgd3guRGlhbG9nLl9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3ZHMpCiAgICAgICAga3dkc1sic3R5bGUiXSA9IGt3ZHMuZ2V0KCJzdHlsZSIsIDApIHwgd3guRkRfU0FWRQogICAgICAgIHd4LkZpbGVEaWFsb2cuX19pbml0X18oc2VsZiwgKmFyZ3MsICoqa3dkcykKICAgICAgICBzZWxmLlNldFRpdGxlKHUi5paw6KaP5L2c5oiQIikKICAgICAgICBzZWxmLkxheW91dCgpCiAgICAgICAgIyBlbmQgd3hHbGFkZQoKIyBlbmQgb2YgY2xhc3MgTmV3RmlsZQoKIyNjbGFzcyBPcGVuRmlsZSh3eC5EaWFsb2cpOiDjgZPjgZPjgpLkv67mraMKY2xhc3MgT3BlbkZpbGUod3guRmlsZURpYWxvZyk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgKmFyZ3MsICoqa3dkcyk6CiAgICAgICAgIyBiZWdpbiB3eEdsYWRlOiBPcGVuRmlsZS5fX2luaXRfXwogICAgICAgIHNlbGYuZW52ID0gYXJnc1swXS5lbnYKIyMgICAgICAgIOasoeOBruS6jOihjOOCkuS/ruatowojIyAgICAgICAga3dkc1sic3R5bGUiXSA9IGt3ZHMuZ2V0KCJzdHlsZSIsIDApIHwgd3guREVGQVVMVF9ESUFMT0dfU1RZTEUKIyMgICAgICAgIHd4LkRpYWxvZy5fX2luaXRfXyhzZWxmLCAqYXJncywgKiprd2RzKQogICAgICAgIGt3ZHNbInN0eWxlIl0gPSBrd2RzLmdldCgic3R5bGUiLCAwKSB8IHd4LkZEX09QRU4KICAgICAgICB3eC5GaWxlRGlhbG9nLl9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3ZHMpCiAgICAgICAgc2VsZi5TZXRUaXRsZSh1IumWi+OBjy4uLiIpCiAgICAgICAgc2VsZi5MYXlvdXQoKQogICAgICAgICMgZW5kIHd4R2xhZGUKCiMgZW5kIG9mIGNsYXNzIE9wZW5GaWxlCgojI2NsYXNzIFNhdmVGaWxlQXMod3guRGlhbG9nKTog44GT44GT44KS5L+u5q2jCmNsYXNzIFNhdmVGaWxlQXMod3guRmlsZURpYWxvZyk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgKmFyZ3MsICoqa3dkcyk6CiAgICAgICAgIyBiZWdpbiB3eEdsYWRlOiBTYXZlRmlsZUFzLl9faW5pdF9fCiAgICAgICAgc2VsZi5lbnYgPSBhcmdzWzBdLmVudgojIyAgICAgICAg5qyh44Gu5LqM6KGM44KS5L+u5q2jCiMjICAgICAgICBrd2RzWyJzdHlsZSJdID0ga3dkcy5nZXQoInN0eWxlIiwgMCkgfCB3eC5ERUZBVUxUX0RJQUxPR19TVFlMRQojIyAgICAgICAgd3guRGlhbG9nLl9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3ZHMpCiAgICAgICAga3dkc1sic3R5bGUiXSA9IGt3ZHMuZ2V0KCJzdHlsZSIsIDApIHwgd3guRkRfU0FWRQogICAgICAgIHd4LkZpbGVEaWFsb2cuX19pbml0X18oc2VsZiwgKmFyZ3MsICoqa3dkcykKICAgICAgICBzZWxmLlNldFRpdGxlKHUi5ZCN5YmN44KS5LuY44GR44Gm5L+d5a2YLi4uIikKICAgICAgICBzZWxmLkxheW91dCgpCiAgICAgICAgIyBlbmQgd3hHbGFkZQoKIyBlbmQgb2YgY2xhc3MgU2F2ZUZpbGVBcwoKY2xhc3MgU2ltcGxlRGF0YWJhc2Uod3guQXBwKToKICAgIGRlZiBPbkluaXQoc2VsZik6CiAgICAgICAgc2VsZi5WaWV3ID0gVmlldyhOb25lLCB3eC5JRF9BTlksICIiKQogICAgICAgIHNlbGYuU2V0VG9wV2luZG93KHNlbGYuVmlldykKICAgICAgICBzZWxmLlZpZXcuU2hvdygpCiAgICAgICAgcmV0dXJuIFRydWUKCiMgZW5kIG9mIGNsYXNzIFNpbXBsZURhdGFiYXNlCgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgbSA9IE1vZGVsKCkgICAgICAgICAgICAgICAgICAgICAgICAjIOi/veWKoDogTW9kZWwKICAgIFNpbXBsZURhdGFiYXNlID0gU2ltcGxlRGF0YWJhc2UoMCkgIyBWaWV3CiAgICBjID0gQ29udHJvbGxlcigpICAgICAgICAgICAgICAgICAgICMg6L+95YqgOiBDb250cm9sbGVyCiAgICBTaW1wbGVEYXRhYmFzZS5NYWluTG9vcCgpCg==