142627b850c8f68a594f105e04b97c512b292b698Ben Gruver/* 242627b850c8f68a594f105e04b97c512b292b698Ben Gruver * Copyright 2013, Google Inc. 342627b850c8f68a594f105e04b97c512b292b698Ben Gruver * All rights reserved. 442627b850c8f68a594f105e04b97c512b292b698Ben Gruver * 542627b850c8f68a594f105e04b97c512b292b698Ben Gruver * Redistribution and use in source and binary forms, with or without 642627b850c8f68a594f105e04b97c512b292b698Ben Gruver * modification, are permitted provided that the following conditions are 742627b850c8f68a594f105e04b97c512b292b698Ben Gruver * met: 842627b850c8f68a594f105e04b97c512b292b698Ben Gruver * 942627b850c8f68a594f105e04b97c512b292b698Ben Gruver * * Redistributions of source code must retain the above copyright 1042627b850c8f68a594f105e04b97c512b292b698Ben Gruver * notice, this list of conditions and the following disclaimer. 1142627b850c8f68a594f105e04b97c512b292b698Ben Gruver * * Redistributions in binary form must reproduce the above 1242627b850c8f68a594f105e04b97c512b292b698Ben Gruver * copyright notice, this list of conditions and the following disclaimer 1342627b850c8f68a594f105e04b97c512b292b698Ben Gruver * in the documentation and/or other materials provided with the 1442627b850c8f68a594f105e04b97c512b292b698Ben Gruver * distribution. 1542627b850c8f68a594f105e04b97c512b292b698Ben Gruver * * Neither the name of Google Inc. nor the names of its 1642627b850c8f68a594f105e04b97c512b292b698Ben Gruver * contributors may be used to endorse or promote products derived from 1742627b850c8f68a594f105e04b97c512b292b698Ben Gruver * this software without specific prior written permission. 1842627b850c8f68a594f105e04b97c512b292b698Ben Gruver * 1942627b850c8f68a594f105e04b97c512b292b698Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2042627b850c8f68a594f105e04b97c512b292b698Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2142627b850c8f68a594f105e04b97c512b292b698Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2242627b850c8f68a594f105e04b97c512b292b698Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2342627b850c8f68a594f105e04b97c512b292b698Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2442627b850c8f68a594f105e04b97c512b292b698Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2542627b850c8f68a594f105e04b97c512b292b698Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2642627b850c8f68a594f105e04b97c512b292b698Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2742627b850c8f68a594f105e04b97c512b292b698Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2842627b850c8f68a594f105e04b97c512b292b698Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2942627b850c8f68a594f105e04b97c512b292b698Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3042627b850c8f68a594f105e04b97c512b292b698Ben Gruver */ 3142627b850c8f68a594f105e04b97c512b292b698Ben Gruver 3242627b850c8f68a594f105e04b97c512b292b698Ben Gruverpackage org.jf.dexlib2.writer.builder; 3342627b850c8f68a594f105e04b97c512b292b698Ben Gruver 3442627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport com.google.common.base.Function; 3542627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport com.google.common.base.Predicate; 3642627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport com.google.common.collect.*; 3742627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.DebugItemType; 389a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruverimport org.jf.dexlib2.builder.MutableMethodImplementation; 396f135aeb74b0a5b5720bafa2a9aaa32880f0549fBen Gruverimport org.jf.dexlib2.iface.ExceptionHandler; 4042627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.iface.Field; 41dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruverimport org.jf.dexlib2.iface.MethodImplementation; 4242627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.iface.TryBlock; 439bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruverimport org.jf.dexlib2.iface.debug.*; 44dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruverimport org.jf.dexlib2.iface.instruction.Instruction; 459bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruverimport org.jf.dexlib2.iface.reference.StringReference; 469bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruverimport org.jf.dexlib2.iface.reference.TypeReference; 4742627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.iface.value.EncodedValue; 4842627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.util.EncodedValueUtils; 4942627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.writer.ClassSection; 5042627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.writer.DebugWriter; 5142627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue; 5242627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.util.AbstractForwardSequentialList; 5342627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.util.CollectionUtils; 5442627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.util.ExceptionWithContext; 5542627b850c8f68a594f105e04b97c512b292b698Ben Gruver 5642627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport javax.annotation.Nonnull; 5742627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport javax.annotation.Nullable; 5842627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport java.io.IOException; 5942627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport java.util.*; 6042627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport java.util.Map.Entry; 6142627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport java.util.concurrent.ConcurrentMap; 6242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 6342627b850c8f68a594f105e04b97c512b292b698Ben Gruverpublic class BuilderClassPool implements ClassSection<BuilderStringReference, BuilderTypeReference, BuilderTypeList, 64ca5de1d8035edbabf0f5a9f8da65d4f6f67db241Ben Gruver BuilderClassDef, BuilderField, BuilderMethod, BuilderAnnotationSet, BuilderEncodedValue> { 6542627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull private final ConcurrentMap<String, BuilderClassDef> internedItems = 6642627b850c8f68a594f105e04b97c512b292b698Ben Gruver Maps.newConcurrentMap(); 6742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 6842627b850c8f68a594f105e04b97c512b292b698Ben Gruver BuilderClassPool() { 6942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 7042627b850c8f68a594f105e04b97c512b292b698Ben Gruver 7142627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull BuilderClassDef internClass(@Nonnull BuilderClassDef classDef) { 7242627b850c8f68a594f105e04b97c512b292b698Ben Gruver BuilderClassDef prev = internedItems.put(classDef.getType(), classDef); 7342627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (prev != null) { 7442627b850c8f68a594f105e04b97c512b292b698Ben Gruver throw new ExceptionWithContext("Class %s has already been interned", classDef.getType()); 7542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 7642627b850c8f68a594f105e04b97c512b292b698Ben Gruver return classDef; 7742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 7842627b850c8f68a594f105e04b97c512b292b698Ben Gruver 7942627b850c8f68a594f105e04b97c512b292b698Ben Gruver private ImmutableList<BuilderClassDef> sortedClasses = null; 8042627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override public Collection<? extends BuilderClassDef> getSortedClasses() { 8142627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (sortedClasses == null) { 8242627b850c8f68a594f105e04b97c512b292b698Ben Gruver sortedClasses = Ordering.natural().immutableSortedCopy(internedItems.values()); 8342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 8442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return sortedClasses; 8542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 8642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 8742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override 8842627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Entry<? extends BuilderClassDef, Integer> getClassEntryByType(@Nullable BuilderTypeReference type) { 8942627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (type == null) { 9042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 9142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 9242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 9342627b850c8f68a594f105e04b97c512b292b698Ben Gruver final BuilderClassDef classDef = internedItems.get(type.getType()); 9442627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (classDef == null) { 9542627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 9642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 9742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 9842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return new Map.Entry<BuilderClassDef, Integer>() { 9942627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public BuilderClassDef getKey() { 10042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return classDef; 10142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 10242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 10342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public Integer getValue() { 10442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return classDef.classDefIndex; 10542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 10642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 10742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public Integer setValue(Integer value) { 10842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return classDef.classDefIndex = value; 10942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 11042627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 11142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 11242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 11342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override public BuilderTypeReference getType(@Nonnull BuilderClassDef builderClassDef) { 11442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.type; 11542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 11642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 11742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getAccessFlags(@Nonnull BuilderClassDef builderClassDef) { 11842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.accessFlags; 11942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 12042627b850c8f68a594f105e04b97c512b292b698Ben Gruver 12142627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public BuilderTypeReference getSuperclass(@Nonnull BuilderClassDef builderClassDef) { 12242627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.superclass; 12342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 12442627b850c8f68a594f105e04b97c512b292b698Ben Gruver 125c456c55c40d0731edb9913fae73f16b9d94ac45bAlex Light @Nullable @Override public BuilderTypeList getInterfaces(@Nonnull BuilderClassDef builderClassDef) { 12642627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.interfaces; 12742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 12842627b850c8f68a594f105e04b97c512b292b698Ben Gruver 12942627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public BuilderStringReference getSourceFile(@Nonnull BuilderClassDef builderClassDef) { 13042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.sourceFile; 13142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 13242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 13342627b850c8f68a594f105e04b97c512b292b698Ben Gruver private static final Predicate<Field> HAS_INITIALIZER = new Predicate<Field>() { 13442627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override 13542627b850c8f68a594f105e04b97c512b292b698Ben Gruver public boolean apply(Field input) { 13642627b850c8f68a594f105e04b97c512b292b698Ben Gruver EncodedValue encodedValue = input.getInitialValue(); 13742627b850c8f68a594f105e04b97c512b292b698Ben Gruver return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue); 13842627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 13942627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 14042627b850c8f68a594f105e04b97c512b292b698Ben Gruver 14142627b850c8f68a594f105e04b97c512b292b698Ben Gruver private static final Function<BuilderField, BuilderEncodedValue> GET_INITIAL_VALUE = 14242627b850c8f68a594f105e04b97c512b292b698Ben Gruver new Function<BuilderField, BuilderEncodedValue>() { 14342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override 14442627b850c8f68a594f105e04b97c512b292b698Ben Gruver public BuilderEncodedValue apply(BuilderField input) { 14542627b850c8f68a594f105e04b97c512b292b698Ben Gruver BuilderEncodedValue initialValue = input.getInitialValue(); 14642627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (initialValue == null) { 14742627b850c8f68a594f105e04b97c512b292b698Ben Gruver return BuilderEncodedValues.defaultValueForType(input.getType()); 14842627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 14942627b850c8f68a594f105e04b97c512b292b698Ben Gruver return initialValue; 15042627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 15142627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 15242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 15342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override 15442627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderEncodedValue> getStaticInitializers(@Nonnull BuilderClassDef classDef) { 15542627b850c8f68a594f105e04b97c512b292b698Ben Gruver final SortedSet<BuilderField> sortedStaticFields = classDef.getStaticFields(); 15642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 15742627b850c8f68a594f105e04b97c512b292b698Ben Gruver final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER); 15842627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (lastIndex > -1) { 15942627b850c8f68a594f105e04b97c512b292b698Ben Gruver return new AbstractCollection<BuilderEncodedValue>() { 16042627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override public Iterator<BuilderEncodedValue> iterator() { 1611d4637b3d94732a4eaa83b129054ee9245bed24eBen Gruver Iterable<BuilderField> fields = Iterables.limit(sortedStaticFields, lastIndex + 1); 1621d4637b3d94732a4eaa83b129054ee9245bed24eBen Gruver return Iterables.transform(fields, GET_INITIAL_VALUE).iterator(); 16342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 16442627b850c8f68a594f105e04b97c512b292b698Ben Gruver 16542627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int size() { 16642627b850c8f68a594f105e04b97c512b292b698Ben Gruver return lastIndex+1; 16742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 16842627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 16942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 17042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 17142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 17242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 17342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 17442627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderField> getSortedStaticFields(@Nonnull BuilderClassDef builderClassDef) { 17542627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.getStaticFields(); 17642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 17742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 17842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 17942627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderField> getSortedInstanceFields(@Nonnull BuilderClassDef builderClassDef) { 18042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.getInstanceFields(); 18142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 18242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 18342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 18442627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderField> getSortedFields(@Nonnull BuilderClassDef builderClassDef) { 18542627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.getFields(); 18642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 18742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 18842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 18942627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderMethod> getSortedDirectMethods(@Nonnull BuilderClassDef builderClassDef) { 19042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.getDirectMethods(); 19142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 19242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 19342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 19442627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderMethod> getSortedVirtualMethods(@Nonnull BuilderClassDef builderClassDef) { 19542627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.getVirtualMethods(); 19642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 19742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 19842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 19942627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Collection<? extends BuilderMethod> getSortedMethods(@Nonnull BuilderClassDef builderClassDef) { 20042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.getMethods(); 20142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 20242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 20342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getFieldAccessFlags(@Nonnull BuilderField builderField) { 20442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderField.accessFlags; 20542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 20642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 20742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getMethodAccessFlags(@Nonnull BuilderMethod builderMethod) { 20842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderMethod.accessFlags; 20942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 21042627b850c8f68a594f105e04b97c512b292b698Ben Gruver 21142627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public BuilderAnnotationSet getClassAnnotations(@Nonnull BuilderClassDef builderClassDef) { 21242627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (builderClassDef.annotations.isEmpty()) { 21342627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 21442627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 21542627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.annotations; 21642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 21742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 21842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public BuilderAnnotationSet getFieldAnnotations(@Nonnull BuilderField builderField) { 21942627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (builderField.annotations.isEmpty()) { 22042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 22142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 22242627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderField.annotations; 22342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 22442627b850c8f68a594f105e04b97c512b292b698Ben Gruver 22542627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public BuilderAnnotationSet getMethodAnnotations(@Nonnull BuilderMethod builderMethod) { 22642627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (builderMethod.annotations.isEmpty()) { 22742627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 22842627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 22942627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderMethod.annotations; 23042627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 23142627b850c8f68a594f105e04b97c512b292b698Ben Gruver 23242627b850c8f68a594f105e04b97c512b292b698Ben Gruver private static final Predicate<BuilderMethodParameter> HAS_PARAMETER_ANNOTATIONS = 23342627b850c8f68a594f105e04b97c512b292b698Ben Gruver new Predicate<BuilderMethodParameter>() { 23442627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override 23542627b850c8f68a594f105e04b97c512b292b698Ben Gruver public boolean apply(BuilderMethodParameter input) { 23642627b850c8f68a594f105e04b97c512b292b698Ben Gruver return input.getAnnotations().size() > 0; 23742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 23842627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 23942627b850c8f68a594f105e04b97c512b292b698Ben Gruver 24042627b850c8f68a594f105e04b97c512b292b698Ben Gruver private static final Function<BuilderMethodParameter, BuilderAnnotationSet> PARAMETER_ANNOTATIONS = 24142627b850c8f68a594f105e04b97c512b292b698Ben Gruver new Function<BuilderMethodParameter, BuilderAnnotationSet>() { 24242627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override 24342627b850c8f68a594f105e04b97c512b292b698Ben Gruver public BuilderAnnotationSet apply(BuilderMethodParameter input) { 24442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return input.getAnnotations(); 24542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 24642627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 24742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 24842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public List<? extends BuilderAnnotationSet> getParameterAnnotations( 24942627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull final BuilderMethod method) { 250f6958ae4bc66ec338f5547ef3952896e219e6c33Ben Gruver final List<? extends BuilderMethodParameter> parameters = method.getParameters(); 251f6958ae4bc66ec338f5547ef3952896e219e6c33Ben Gruver boolean hasParameterAnnotations = Iterables.any(parameters, HAS_PARAMETER_ANNOTATIONS); 25242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 253f6958ae4bc66ec338f5547ef3952896e219e6c33Ben Gruver if (hasParameterAnnotations) { 25442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return new AbstractForwardSequentialList<BuilderAnnotationSet>() { 25542627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override public Iterator<BuilderAnnotationSet> iterator() { 2561d4637b3d94732a4eaa83b129054ee9245bed24eBen Gruver return Iterables.transform(parameters, PARAMETER_ANNOTATIONS).iterator(); 25742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 25842627b850c8f68a594f105e04b97c512b292b698Ben Gruver 25942627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int size() { 260f6958ae4bc66ec338f5547ef3952896e219e6c33Ben Gruver return parameters.size(); 26142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 26242627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 26342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 26442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 26542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 26642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 26742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override 2689bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver public Iterable<? extends DebugItem> getDebugItems(@Nonnull BuilderMethod builderMethod) { 269dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver MethodImplementation impl = builderMethod.getImplementation(); 27042627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (impl == null) { 27142627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 27242627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 27342627b850c8f68a594f105e04b97c512b292b698Ben Gruver return impl.getDebugItems(); 27442627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 27542627b850c8f68a594f105e04b97c512b292b698Ben Gruver 27642627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override 27742627b850c8f68a594f105e04b97c512b292b698Ben Gruver public Iterable<? extends BuilderStringReference> getParameterNames(@Nonnull BuilderMethod method) { 27842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return Iterables.transform(method.getParameters(), new Function<BuilderMethodParameter, BuilderStringReference>() { 27942627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override public BuilderStringReference apply(BuilderMethodParameter input) { 28042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return input.name; 28142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 28242627b850c8f68a594f105e04b97c512b292b698Ben Gruver }); 28342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 28442627b850c8f68a594f105e04b97c512b292b698Ben Gruver 28542627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getRegisterCount(@Nonnull BuilderMethod builderMethod) { 286dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver MethodImplementation impl = builderMethod.getImplementation(); 28742627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (impl == null) { 28842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return 0; 28942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 290dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver return impl.getRegisterCount(); 29142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 29242627b850c8f68a594f105e04b97c512b292b698Ben Gruver 29342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nullable @Override 294dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver public Iterable<? extends Instruction> getInstructions(@Nonnull BuilderMethod builderMethod) { 295dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver MethodImplementation impl = builderMethod.getImplementation(); 29642627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (impl == null) { 29742627b850c8f68a594f105e04b97c512b292b698Ben Gruver return null; 29842627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 29942627b850c8f68a594f105e04b97c512b292b698Ben Gruver return impl.getInstructions(); 30042627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 30142627b850c8f68a594f105e04b97c512b292b698Ben Gruver 30242627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override 303dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(@Nonnull BuilderMethod builderMethod) { 304dff046e1b559f4f8b175bb9cdaf005419ec62cb1Ben Gruver MethodImplementation impl = builderMethod.getImplementation(); 30542627b850c8f68a594f105e04b97c512b292b698Ben Gruver if (impl == null) { 30642627b850c8f68a594f105e04b97c512b292b698Ben Gruver return ImmutableList.of(); 30742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 30842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return impl.getTryBlocks(); 30942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 31042627b850c8f68a594f105e04b97c512b292b698Ben Gruver 3116f135aeb74b0a5b5720bafa2a9aaa32880f0549fBen Gruver @Nullable @Override public BuilderTypeReference getExceptionType(@Nonnull ExceptionHandler handler) { 3126f135aeb74b0a5b5720bafa2a9aaa32880f0549fBen Gruver return checkTypeReference(handler.getExceptionTypeReference()); 31342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 31442627b850c8f68a594f105e04b97c512b292b698Ben Gruver 3159a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver @Nonnull @Override 3169a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver public MutableMethodImplementation makeMutableMethodImplementation(@Nonnull BuilderMethod builderMethod) { 3179a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver MethodImplementation impl = builderMethod.getImplementation(); 3189a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver if (impl instanceof MutableMethodImplementation) { 3199a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver return (MutableMethodImplementation)impl; 3209a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver } 3219a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver return new MutableMethodImplementation(impl); 3229a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver } 3239a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver 32442627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public void setEncodedArrayOffset(@Nonnull BuilderClassDef builderClassDef, int offset) { 32542627b850c8f68a594f105e04b97c512b292b698Ben Gruver builderClassDef.encodedArrayOffset = offset; 32642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 32742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 32842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getEncodedArrayOffset(@Nonnull BuilderClassDef builderClassDef) { 32942627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.encodedArrayOffset; 33042627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 33142627b850c8f68a594f105e04b97c512b292b698Ben Gruver 33242627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public void setAnnotationDirectoryOffset(@Nonnull BuilderClassDef builderClassDef, int offset) { 33342627b850c8f68a594f105e04b97c512b292b698Ben Gruver builderClassDef.annotationDirectoryOffset = offset; 33442627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 33542627b850c8f68a594f105e04b97c512b292b698Ben Gruver 33642627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getAnnotationDirectoryOffset(@Nonnull BuilderClassDef builderClassDef) { 33742627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.annotationDirectoryOffset; 33842627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 33942627b850c8f68a594f105e04b97c512b292b698Ben Gruver 34042627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public void setAnnotationSetRefListOffset(@Nonnull BuilderMethod builderMethod, int offset) { 34142627b850c8f68a594f105e04b97c512b292b698Ben Gruver builderMethod.annotationSetRefListOffset = offset; 34242627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 34342627b850c8f68a594f105e04b97c512b292b698Ben Gruver 34442627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getAnnotationSetRefListOffset(@Nonnull BuilderMethod builderMethod) { 34542627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderMethod.annotationSetRefListOffset; 34642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 34742627b850c8f68a594f105e04b97c512b292b698Ben Gruver 34842627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public void setCodeItemOffset(@Nonnull BuilderMethod builderMethod, int offset) { 34942627b850c8f68a594f105e04b97c512b292b698Ben Gruver builderMethod.codeItemOffset = offset; 35042627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 35142627b850c8f68a594f105e04b97c512b292b698Ben Gruver 35242627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getCodeItemOffset(@Nonnull BuilderMethod builderMethod) { 35342627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderMethod.codeItemOffset; 35442627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 35542627b850c8f68a594f105e04b97c512b292b698Ben Gruver 3569bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver @Nullable private BuilderStringReference checkStringReference(@Nullable StringReference stringReference) { 3579bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver if (stringReference == null) { 3589bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver return null; 3599bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } 3609bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver try { 3619bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver return (BuilderStringReference)stringReference; 3629bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } catch (ClassCastException ex) { 3639bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver throw new IllegalStateException("Only StringReference instances returned by " + 3649bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver "DexBuilder.internStringReference or DexBuilder.internNullableStringReference may be used."); 3659bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } 3669bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } 3679bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver 3689bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver @Nullable private BuilderTypeReference checkTypeReference(@Nullable TypeReference typeReference) { 3699bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver if (typeReference == null) { 3709bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver return null; 3719bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } 3729bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver try { 3739bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver return (BuilderTypeReference)typeReference; 3749bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } catch (ClassCastException ex) { 3759bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver throw new IllegalStateException("Only TypeReference instances returned by " + 3769bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver "DexBuilder.internTypeReference or DexBuilder.internNullableTypeReference may be used."); 3779bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } 3789bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver } 3799bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver 38042627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override 38142627b850c8f68a594f105e04b97c512b292b698Ben Gruver public void writeDebugItem(@Nonnull DebugWriter<BuilderStringReference, BuilderTypeReference> writer, 3829bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver DebugItem debugItem) throws IOException { 38342627b850c8f68a594f105e04b97c512b292b698Ben Gruver switch (debugItem.getDebugItemType()) { 38442627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.START_LOCAL: { 3859bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver StartLocal startLocal = (StartLocal)debugItem; 38642627b850c8f68a594f105e04b97c512b292b698Ben Gruver writer.writeStartLocal(startLocal.getCodeAddress(), 3879bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver startLocal.getRegister(), 3889bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver checkStringReference(startLocal.getNameReference()), 3899bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver checkTypeReference(startLocal.getTypeReference()), 3909bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver checkStringReference(startLocal.getSignatureReference())); 39142627b850c8f68a594f105e04b97c512b292b698Ben Gruver break; 39242627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 39342627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.END_LOCAL: { 39442627b850c8f68a594f105e04b97c512b292b698Ben Gruver EndLocal endLocal = (EndLocal)debugItem; 39542627b850c8f68a594f105e04b97c512b292b698Ben Gruver writer.writeEndLocal(endLocal.getCodeAddress(), endLocal.getRegister()); 39642627b850c8f68a594f105e04b97c512b292b698Ben Gruver break; 39742627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 39842627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.RESTART_LOCAL: { 39942627b850c8f68a594f105e04b97c512b292b698Ben Gruver RestartLocal restartLocal = (RestartLocal)debugItem; 40042627b850c8f68a594f105e04b97c512b292b698Ben Gruver writer.writeRestartLocal(restartLocal.getCodeAddress(), restartLocal.getRegister()); 40142627b850c8f68a594f105e04b97c512b292b698Ben Gruver break; 40242627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 40342627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.PROLOGUE_END: { 40442627b850c8f68a594f105e04b97c512b292b698Ben Gruver writer.writePrologueEnd(debugItem.getCodeAddress()); 40542627b850c8f68a594f105e04b97c512b292b698Ben Gruver break; 40642627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 40742627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.EPILOGUE_BEGIN: { 40842627b850c8f68a594f105e04b97c512b292b698Ben Gruver writer.writeEpilogueBegin(debugItem.getCodeAddress()); 40942627b850c8f68a594f105e04b97c512b292b698Ben Gruver break; 41042627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 41142627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.LINE_NUMBER: { 41242627b850c8f68a594f105e04b97c512b292b698Ben Gruver LineNumber lineNumber = (LineNumber)debugItem; 41342627b850c8f68a594f105e04b97c512b292b698Ben Gruver writer.writeLineNumber(lineNumber.getCodeAddress(), lineNumber.getLineNumber()); 41442627b850c8f68a594f105e04b97c512b292b698Ben Gruver break; 41542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 41642627b850c8f68a594f105e04b97c512b292b698Ben Gruver case DebugItemType.SET_SOURCE_FILE: { 4179bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver SetSourceFile setSourceFile = (SetSourceFile)debugItem; 4189bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver writer.writeSetSourceFile(setSourceFile.getCodeAddress(), 4199bbcaae91fffe74cbc90608eaa98484192b11d77Ben Gruver checkStringReference(setSourceFile.getSourceFileReference())); 420a37e508ffa2a512d70890c6a174c2c98ed803607Ben Gruver break; 42142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 42242627b850c8f68a594f105e04b97c512b292b698Ben Gruver default: 42342627b850c8f68a594f105e04b97c512b292b698Ben Gruver throw new ExceptionWithContext("Unexpected debug item type: %d", debugItem.getDebugItemType()); 42442627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 42542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 42642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 42742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override public int getItemIndex(@Nonnull BuilderClassDef builderClassDef) { 42842627b850c8f68a594f105e04b97c512b292b698Ben Gruver return builderClassDef.classDefIndex; 42942627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 43042627b850c8f68a594f105e04b97c512b292b698Ben Gruver 43142627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Nonnull @Override public Collection<? extends Entry<? extends BuilderClassDef, Integer>> getItems() { 43242627b850c8f68a594f105e04b97c512b292b698Ben Gruver return new BuilderMapEntryCollection<BuilderClassDef>(internedItems.values()) { 43342627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override protected int getValue(@Nonnull BuilderClassDef key) { 43442627b850c8f68a594f105e04b97c512b292b698Ben Gruver return key.classDefIndex; 43542627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 43642627b850c8f68a594f105e04b97c512b292b698Ben Gruver 43742627b850c8f68a594f105e04b97c512b292b698Ben Gruver @Override protected int setValue(@Nonnull BuilderClassDef key, int value) { 43842627b850c8f68a594f105e04b97c512b292b698Ben Gruver int prev = key.classDefIndex; 43942627b850c8f68a594f105e04b97c512b292b698Ben Gruver key.classDefIndex = value; 44042627b850c8f68a594f105e04b97c512b292b698Ben Gruver return prev; 44142627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 44242627b850c8f68a594f105e04b97c512b292b698Ben Gruver }; 44342627b850c8f68a594f105e04b97c512b292b698Ben Gruver } 44442627b850c8f68a594f105e04b97c512b292b698Ben Gruver} 445