1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59f606f95f03a75961498803e24bee6799a7c0885Ying Wang * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.gui; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.ClassSpecification; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.ClassUtil; 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport javax.swing.*; 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.awt.*; 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.awt.event.*; 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.*; 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.List; 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This <code>ListPanel</code> allows the user to add, edit, move, and remove 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ClassSpecification entries in a list. 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoclass ClassSpecificationsPanel extends ListPanel 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected final ClassSpecificationDialog classSpecificationDialog; 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public ClassSpecificationsPanel(JFrame owner, boolean fullKeepOptions) 45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato super(); 47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato list.setCellRenderer(new MyListCellRenderer()); 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato classSpecificationDialog = new ClassSpecificationDialog(owner, fullKeepOptions); 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addAddButton(); 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addEditButton(); 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addRemoveButton(); 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addUpButton(); 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addDownButton(); 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato enableSelectionButtons(); 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected void addAddButton() 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato JButton addButton = new JButton(msg("add")); 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addButton.addActionListener(new ActionListener() 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void actionPerformed(ActionEvent e) 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato setClassSpecification(createClassSpecification()); 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int returnValue = classSpecificationDialog.showDialog(); 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (returnValue == ClassSpecificationDialog.APPROVE_OPTION) 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Add the new element. 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addElement(getClassSpecification()); 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato }); 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addButton(tip(addButton, "addTip")); 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected void addEditButton() 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato JButton editButton = new JButton(msg("edit")); 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato editButton.addActionListener(new ActionListener() 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void actionPerformed(ActionEvent e) 89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassSpecification selectedClassSpecification = 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (ClassSpecification)list.getSelectedValue(); 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato setClassSpecification(selectedClassSpecification); 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int returnValue = classSpecificationDialog.showDialog(); 95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (returnValue == ClassSpecificationDialog.APPROVE_OPTION) 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Replace the old element. 98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato setElementAt(getClassSpecification(), 99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato list.getSelectedIndex()); 100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato }); 103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato addButton(tip(editButton, "editTip")); 105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected ClassSpecification createClassSpecification() 109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return new ClassSpecification(); 111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected void setClassSpecification(ClassSpecification classSpecification) 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato classSpecificationDialog.setClassSpecification(classSpecification); 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected ClassSpecification getClassSpecification() 121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return classSpecificationDialog.getClassSpecification(); 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Sets the ClassSpecification objects to be represented in this panel. 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void setClassSpecifications(List classSpecifications) 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato listModel.clear(); 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (classSpecifications != null) 134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato for (int index = 0; index < classSpecifications.size(); index++) 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato listModel.addElement(classSpecifications.get(index)); 138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Make sure the selection buttons are properly enabled, 142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // since the clear method doesn't seem to notify the listener. 143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato enableSelectionButtons(); 144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the ClassSpecification objects currently represented in this panel. 149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public List getClassSpecifications() 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int size = listModel.size(); 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (size == 0) 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return null; 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato List classSpecifications = new ArrayList(size); 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato for (int index = 0; index < size; index++) 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato classSpecifications.add(listModel.get(index)); 162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return classSpecifications; 165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Attaches the tool tip from the GUI resources that corresponds to the 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * given key, to the given component. 171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static JComponent tip(JComponent component, String messageKey) 173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato component.setToolTipText(msg(messageKey)); 175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return component; 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the message from the GUI resources that corresponds to the given 182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * key. 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static String msg(String messageKey) 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return GUIResources.getMessage(messageKey); 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This ListCellRenderer renders ClassSpecification objects. 192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static class MyListCellRenderer implements ListCellRenderer 194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private final JLabel label = new JLabel(); 196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for ListCellRenderer. 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public Component getListCellRendererComponent(JList list, 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Object value, 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int index, 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato boolean isSelected, 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato boolean cellHasFocus) 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassSpecification classSpecification = (ClassSpecification)value; 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String comments = classSpecification.comments; 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato label.setText(comments != null ? comments.trim() : 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato classSpecification.className != null ? (msg("class") + ' ' + ClassUtil.externalClassName(classSpecification.className)) : 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato classSpecification.extendsClassName != null ? (msg("extensionsOf") + ' ' + ClassUtil.externalClassName(classSpecification.extendsClassName)) : 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (msg("specificationNumber") + index)); 214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (isSelected) 216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato label.setBackground(list.getSelectionBackground()); 218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato label.setForeground(list.getSelectionForeground()); 219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato label.setBackground(list.getBackground()); 223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato label.setForeground(list.getForeground()); 224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato label.setOpaque(true); 227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return label; 229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato} 232