Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/kmcaster.git

Double-buffering, flicker reduction

Author DaveJarvis <email>
Date 2020-07-20 23:04:55 GMT-0700
Commit 1f921dc8e1260eafe0a08f93aa30ce30920f04b7
Parent 8dbfba9
src/main/com/whitemagicsoftware/kmcaster/EventHandler.java
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.util.Map;
import static com.whitemagicsoftware.kmcaster.HardwareState.ANY_KEY;
import static java.awt.Font.BOLD;
import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
import static java.lang.Math.abs;
import static javax.swing.SwingConstants.CENTER;
*/
private static final Font LABEL_FONT = new Font( "DejaVu Sans", BOLD, 32 );
+
+ private static final String KEY_UP = FALSE.toString();
+ private static final String KEY_DOWN = TRUE.toString();
/**
- * Matches the shift-key arrow font colour.
+ * Matches the shift-key arrow font colour when pressed.
*/
- private static final Color LABEL_COLOUR = new Color( 33, 33, 33 );
+ private static final Color COLOUR_KEY_DN = new Color( 0x21, 0x21, 0x21 );
+
+ /**
+ * Matches the shift-key arrow font colour when released.
+ */
+ private static final Color COLOUR_KEY_UP = new Color( 0xE5, 0xE5, 0xE5 );
+
+ /**
+ * Maps key pressed states to key cap title colours.
+ */
+ private static final Map<String, Color> KEY_COLOURS = Map.of(
+ KEY_DOWN, COLOUR_KEY_DN,
+ KEY_UP, COLOUR_KEY_UP
+ );
private final HardwareImages mHardwareImages;
// released (doesn't matter what kind of key).
final var context =
- (!"false".equals( switchValue ) && !"true".equals( switchValue ))
+ (!KEY_UP.equals( switchValue ) && !KEY_DOWN.equals( switchValue ))
? ANY_KEY
: switchValue;
protected void updateSwitchLabel(
final HardwareState state, final String value ) {
- if( state.isModifier() ) {
-// final var label = new AutofitLabel( value, LABEL_FONT, LABEL_COLOUR );
-// label.setVisible( false );
- System.out.println( state.getHardwareSwitch().toTitleCase() );
+ final var container = getHardwareComponent( state );
+
+ if( KEY_UP.equals( value ) ) {
+ container.removeAll();
}
- else {
- final var container = getHardwareComponent( state );
+
+ if( state.isModifier() ) {
+ final var hwSwitch = state.getHardwareSwitch();
+ final var switchName = hwSwitch.toTitleCase();
+ final var keyColour = KEY_COLOURS.get( value );
+
+ final var label = new AutofitLabel( switchName, LABEL_FONT, keyColour );
+ label.setVisible( false );
+ label.setHorizontalAlignment( CENTER );
+ label.setVerticalAlignment( CENTER );
container.removeAll();
+ container.add( label );
+ label.setVisible( true );
+ }
+ else if( !KEY_UP.equals( value ) ) {
+ // A non-modifier key has been pressed.
+ final var index = value.indexOf( ' ' );
+ final var keyColour = KEY_COLOURS.get( KEY_DOWN );
- if( !FALSE.toString().equals( value ) ) {
- final var index = value.indexOf( ' ' );
+ // If there's a space in the name, the text before the space is
+ // positioned in the upper-left while the text afterwards takes up
+ // the remainder. This is used for number pad keys, backspace, enter,
+ // tab, and a few others.
+ if( index > 0 ) {
+ final var calculator = new BoundsCalculator( container );
+ final var contDimen = new ScalableDimension( calculator.computeSize() );
+ final var supSize = contDimen.scale( .6f );
+ final var mainSize = contDimen.scale( .9f );
- // If there's a space in the name, the text before the space is
- // positioned in the upper-left while the text afterwards takes up
- // the remainder. This is used for number pad keys, backspace, enter,
- // tab, and a few others.
- if( index > 0 ) {
- final var calculator = new BoundsCalculator( container );
- final var bounds = calculator.computeSize();
- final var containerDim = new ScalableDimension( bounds );
+ final var s = new String[]{
+ value.substring( 0, index ),
+ value.substring( index + 1 )
+ };
- final var s = new String[]{
- value.substring( 0, index ),
- value.substring( index + 1 )
- };
+ // Label for "Num", "Back", "Tab", and other dual-labelled keys.
+ final var sup = new AutofitLabel( s[ 0 ], LABEL_FONT, keyColour );
+ sup.setVisible( false );
+ sup.setVerticalAlignment( TOP );
- // "Num", "Back", "Tab", and other superscript contextual keys.
- final var sup = new AutofitLabel( s[ 0 ], LABEL_FONT, LABEL_COLOUR );
- sup.setVisible( false );
- container.add( sup );
- sup.setVerticalAlignment( TOP );
- sup.setSize( containerDim.scale( .6f ) );
- sup.setVisible( true );
+ // Label for number pad keys or icon glyphs.
+ final var main = new AutofitLabel( s[ 1 ], LABEL_FONT, keyColour );
+ main.setVisible( false );
+ main.setHorizontalAlignment( CENTER );
+ main.setVerticalAlignment( CENTER );
- // Number pad keys or icon glyphs.
- final var main = new AutofitLabel( s[ 1 ], LABEL_FONT, LABEL_COLOUR );
- main.setVisible( false );
- container.add( main );
- main.setSize( containerDim.scale( .9f ) );
- main.setHorizontalAlignment( CENTER );
- main.setVerticalAlignment( CENTER );
+ // Keep removing then adding as close together as possible to minimize
+ // flicker.
+ container.removeAll();
+ container.add( main );
+ container.add( sup );
+ main.setSize( mainSize );
+ sup.setSize( supSize );
- // Center-align the main text with respect to the container.
- final var location = main.getLocation();
- final var dx = abs( containerDim.getWidth() - main.getWidth() ) / 2;
- final var dy = abs( containerDim.getHeight() - main.getHeight() ) / 2;
+ // Center-align the main text with respect to the container.
+ final var location = main.getLocation();
+ final var dx = abs( contDimen.getWidth() - main.getWidth() ) / 2;
+ final var dy = abs( contDimen.getHeight() - main.getHeight() ) / 2;
- // Shift the main text down a smidgen, relative to the superscript.
- main.setLocation(
- (int) (location.getX() + dx),
- (int) (location.getY() + dy) + sup.getHeight() / 4 );
- main.setVisible( true );
- }
- else {
- // Single keys need no tweaking and can be added to the container
- // directly. The horizontal and vertical alignments
- final var label = new AutofitLabel( value, LABEL_FONT, LABEL_COLOUR );
- label.setVisible( false );
- container.add( label );
- label.setHorizontalAlignment( CENTER );
- label.setVerticalAlignment( CENTER );
- label.setVisible( true );
- }
+ // Shift the main text down a smidgen, relative to the superscript.
+ main.setLocation(
+ (int) (location.getX() + dx),
+ (int) (location.getY() + dy) + sup.getHeight() / 4 );
+ main.setVisible( true );
+ sup.setVisible( true );
+ }
+ else {
+ // Single keys need no tweaking and can be added to the container
+ // directly. The horizontal and vertical alignments
+ final var label = new AutofitLabel( value, LABEL_FONT, keyColour );
+ label.setVisible( false );
+ label.setHorizontalAlignment( CENTER );
+ label.setVerticalAlignment( CENTER );
+ container.removeAll();
+ container.add( label );
+ label.setVisible( true );
}
}
src/main/com/whitemagicsoftware/kmcaster/HardwareComponent.java
*/
public HardwareComponent( final Insets insets ) {
+ setDoubleBuffered( true );
mInsets = insets;
}
src/main/com/whitemagicsoftware/kmcaster/HardwareImages.java
);
+ /**
+ * Defines the amount of space between around the vector graphic projection
+ * of a key. These values are specific to the projected sizes and must be
+ * measured while editing the vector graphic (e.g., using the ruler tool),
+ * rounded up then codified here. The insets will be scaled to fit the
+ * application window frame.
+ * <p>
+ * The shift key insets offset the safe area to the right of the up arrow
+ * icon.
+ * </p>
+ */
+ private final static Map<HardwareSwitch, Insets> SWITCH_INSETS = Map.of(
+ KEY_ALT, new Insets( 8, 11, 12, 11 ),
+ KEY_CTRL, new Insets( 8, 11, 12, 11 ),
+ KEY_SHIFT, new Insets( 5, 50, 9, 11 ),
+ KEY_REGULAR, new Insets( 3, 7, 6, 7 )
+ );
+
private final static SvgRasterizer sRasterizer = new SvgRasterizer();
final var imageUp = keyUpImage( FILE_NAME_PREFIXES.get( key ) );
final var scale = imageDn.getValue();
+ final var insets = new KeyCapInsets( SWITCH_INSETS.get(key) );
+ final var scaledInsets = insets.scale( scale );
- final var insets = KeyCapInsets.scale( scale );
- final var hardwareComponent = createHardwareComponent( insets );
+ final var hardwareComponent = createHardwareComponent( scaledInsets );
hardwareComponent.put( stateOn, imageDn.getKey() );
src/main/com/whitemagicsoftware/kmcaster/KeyCapInsets.java
* mouse images have neither insets nor padding.
*/
-public class KeyCapInsets {
- /**
- * Defines the amount of space between the 3D base of a key and the 3D
- * top of the key; the vector graphic is a 2D projection and these values
- * are specific to the projected sizes.
- */
- private final static Insets INSET_PROJECTED =
- new Insets( 3, 7, 6, 7 );
-
+public final class KeyCapInsets {
/**
* Defines the padding around the inside of the key cap to give the letters
* some whitespace.
*/
private final static Insets INSET_PADDING =
new Insets( 4, 4, 4, 4 );
- private final static Insets INSET_TOTAL =
- new Insets(
- INSET_PROJECTED.top + INSET_PADDING.top,
- INSET_PROJECTED.left + INSET_PADDING.left,
- INSET_PROJECTED.bottom + INSET_PADDING.bottom,
- INSET_PROJECTED.right + INSET_PADDING.right
- );
+ /**
+ * Includes safe zone and internal padding.
+ */
+ private final Insets mInsets;
+
+ /**
+ * Creates a new area for drawing on a key cap. This class will add an
+ * internal padding amount.
+ *
+ * @param insets The insets that correlate the "safe zone" for drawing
+ * items on the key cap, without padding.
+ */
+ public KeyCapInsets( final Insets insets ) {
+ mInsets = new Insets(
+ insets.top + INSET_PADDING.top,
+ insets.left + INSET_PADDING.left,
+ insets.bottom + INSET_PADDING.bottom,
+ insets.right + INSET_PADDING.right
+ );
+ }
/**
* Scales the image insets and padding.
*/
- public static Insets scale( final DimensionTuple factor ) {
+ public Insets scale( final DimensionTuple factor ) {
final var wRatio = factor.getWidthRatio();
final var hRatio = factor.getHeightRatio();
return new Insets(
- (int) (INSET_TOTAL.top * hRatio),
- (int) (INSET_TOTAL.left * wRatio),
- (int) (INSET_TOTAL.bottom * hRatio),
- (int) (INSET_TOTAL.right * wRatio) );
+ (int) (mInsets.top * hRatio),
+ (int) (mInsets.left * wRatio),
+ (int) (mInsets.bottom * hRatio),
+ (int) (mInsets.right * wRatio) );
}
}
src/main/com/whitemagicsoftware/kmcaster/ui/AutofitLabel.java
public AutofitLabel( final String text, final Font font, final Color color ) {
super( text );
+ setDoubleBuffered( true );
setFont( font );
setForeground( color );
src/main/resources/images/key/dn/long.svg
-<svg height="60" viewBox="0 0 37.042 15.875" width="140" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(-.060888 0 0 .060336 56.497 -18.194)" gradientUnits="userSpaceOnUse" x1="338.63" x2="358.68" y1="522.48" y2="538.13"><stop offset="0" stop-color="#d6d6d6"/><stop offset="1" stop-color="#939393"/></linearGradient><linearGradient id="b" gradientTransform="matrix(.36493 0 0 .36162 -33.305 -67.568)" gradientUnits="userSpaceOnUse" x1="93.499" x2="97.32" y1="223.35" y2="225.96"><stop offset="0" stop-color="#656565"/><stop offset="1" stop-color="#939393"/></linearGradient><linearGradient id="c" gradientTransform="matrix(.36493 0 0 .36162 -33.305 -67.568)" gradientUnits="userSpaceOnUse" x1="186.6" x2="186.1" y1="190.18" y2="188.08"><stop offset="0" stop-color="#d6d6d6"/><stop offset="1" stop-color="#656565"/></linearGradient><linearGradient id="d" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="127.4" x2="167.04" y1="207.21" y2="207.21"><stop offset="0" stop-color="#d8d8d8"/><stop offset="1" stop-color="#b1b1b1"/></linearGradient><linearGradient id="e" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="97.58" x2="128.18" y1="202.35" y2="202.35"><stop offset="0" stop-color="#f1f1f1"/><stop offset="1" stop-color="#c1c1c1"/></linearGradient><g fill-rule="evenodd" stroke-width=".36327"><path d="m.84701 0h33.741c.46924 0 .84701.37434.84701.83932v10.724h-35.423l-.011539-10.724c-.0005474-.46498.37776-.83932.847-.83932z" fill="#656565"/><path d="m2.5208 13.795h31.832v2.0735h-31.832z" fill="#929292"/><path d="m32.91 1.1636h4.1317l.000004 10.408h-4.1317z" fill="#d6d6d6"/><path d="m33.878 11.228 3.1637.34396-.000004 3.0387c-.0015.78594-.63212 1.2375-1.2839 1.2647l-1.4053-.007-1.5509-3.5889z" fill="url(#a)"/><path d="m2.195 11.197-2.1835.36569-.011539 3.0474c.0016422.78594.63212 1.2375 1.2839 1.2647l1.4031-.01522.49205-3.5655z" fill="url(#b)"/><path d="m34.389 2.0256 2.653-.86194c-.10539-.82869-.6792-1.1252-1.4787-1.1421-.20536-.0043395-.37419-.01602-.59203-.019672-.21784-.0036886-.71487-.00035801-.71487-.00035801-.50121.097262-.89355.38179-1.1678.84836z" fill="url(#c)"/></g><rect fill="url(#d)" fill-rule="evenodd" height="12.812" ry=".97192" stroke="url(#e)" stroke-width=".26459" width="32.55" x="2.246" y=".95721"/><path d="m4.3714 7.7022h2.4614v2.8001h3.0769v-2.8024h2.4616l-4-3.4159z" fill="none" stroke="#333" stroke-width=".77404"/></svg>
+<svg height="60" viewBox="0 0 37.042 15.875" width="140" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(-.060888 0 0 .060336 56.497 -18.194)" gradientUnits="userSpaceOnUse" x1="338.63" x2="358.68" y1="522.48" y2="538.13"><stop offset="0" stop-color="#d6d6d6"/><stop offset="1" stop-color="#939393"/></linearGradient><linearGradient id="b" gradientTransform="matrix(.36493 0 0 .36162 -33.305 -67.568)" gradientUnits="userSpaceOnUse" x1="93.499" x2="97.32" y1="223.35" y2="225.96"><stop offset="0" stop-color="#656565"/><stop offset="1" stop-color="#939393"/></linearGradient><linearGradient id="c" gradientTransform="matrix(.36493 0 0 .36162 -33.305 -67.568)" gradientUnits="userSpaceOnUse" x1="186.6" x2="186.1" y1="190.18" y2="188.08"><stop offset="0" stop-color="#d6d6d6"/><stop offset="1" stop-color="#656565"/></linearGradient><linearGradient id="d" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="127.4" x2="167.04" y1="207.21" y2="207.21"><stop offset="0" stop-color="#d8d8d8"/><stop offset="1" stop-color="#b1b1b1"/></linearGradient><linearGradient id="e" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="97.58" x2="128.18" y1="202.35" y2="202.35"><stop offset="0" stop-color="#f1f1f1"/><stop offset="1" stop-color="#c1c1c1"/></linearGradient><g fill-rule="evenodd" stroke-width=".36327"><path d="m.84701 0h33.741c.46924 0 .84701.37434.84701.83932v10.724h-35.423l-.011539-10.724c-.0005474-.46498.37776-.83932.847-.83932z" fill="#656565"/><path d="m2.5208 13.795h31.832v2.0735h-31.832z" fill="#929292"/><path d="m32.91 1.1636h4.1317l.000004 10.408h-4.1317z" fill="#d6d6d6"/><path d="m33.878 11.228 3.1637.34396-.000004 3.0387c-.0015.78594-.63212 1.2375-1.2839 1.2647l-1.4053-.007-1.5509-3.5889z" fill="url(#a)"/><path d="m2.195 11.197-2.1835.36569-.011539 3.0474c.0016422.78594.63212 1.2375 1.2839 1.2647l1.4031-.01522.49205-3.5655z" fill="url(#b)"/><path d="m34.389 2.0256 2.653-.86194c-.10539-.82869-.6792-1.1252-1.4787-1.1421-.20536-.0043395-.37419-.01602-.59203-.019672-.21784-.0036886-.71487-.00035801-.71487-.00035801-.50121.097262-.89355.38179-1.1678.84836z" fill="url(#c)"/></g><rect fill="url(#d)" fill-rule="evenodd" height="12.812" ry=".97192" stroke="url(#e)" stroke-width=".26459" width="32.55" x="2.246" y=".95721"/><path d="m4.482 7.7355h2.4519v2.8124h3.065v-2.8147h2.4521l-3.9845-3.4309z" fill="none" stroke="#333" stroke-width=".77424"/></svg>
src/main/resources/images/key/dn/sm-long.svg
-
+<svg height="60" viewBox="0 0 37.042 15.875" width="140" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(-.060888 0 0 .060336 56.497 -18.194)" gradientUnits="userSpaceOnUse" x1="338.63" x2="358.68" y1="522.48" y2="538.13"><stop offset="0" stop-color="#d6d6d6"/><stop offset="1" stop-color="#939393"/></linearGradient><linearGradient id="b" gradientTransform="matrix(.36493 0 0 .36162 -33.305 -67.568)" gradientUnits="userSpaceOnUse" x1="93.499" x2="97.32" y1="223.35" y2="225.96"><stop offset="0" stop-color="#656565"/><stop offset="1" stop-color="#939393"/></linearGradient><linearGradient id="c" gradientTransform="matrix(.36493 0 0 .36162 -33.305 -67.568)" gradientUnits="userSpaceOnUse" x1="186.6" x2="186.1" y1="190.18" y2="188.08"><stop offset="0" stop-color="#d6d6d6"/><stop offset="1" stop-color="#656565"/></linearGradient><linearGradient id="d" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="127.4" x2="167.04" y1="207.21" y2="207.21"><stop offset="0" stop-color="#d8d8d8"/><stop offset="1" stop-color="#b1b1b1"/></linearGradient><linearGradient id="e" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="97.58" x2="128.18" y1="202.35" y2="202.35"><stop offset="0" stop-color="#f1f1f1"/><stop offset="1" stop-color="#c1c1c1"/></linearGradient><g fill-rule="evenodd" stroke-width=".36327"><path d="m.84701 0h33.741c.46924 0 .84701.37434.84701.83932v10.724h-35.423l-.011539-10.724c-.0005474-.46498.37776-.83932.847-.83932z" fill="#656565"/><path d="m2.5208 13.795h31.832v2.0735h-31.832z" fill="#929292"/><path d="m32.91 1.1636h4.1317l.000004 10.408h-4.1317z" fill="#d6d6d6"/><path d="m33.878 11.228 3.1637.34396-.000004 3.0387c-.0015.78594-.63212 1.2375-1.2839 1.2647l-1.4053-.007-1.5509-3.5889z" fill="url(#a)"/><path d="m2.195 11.197-2.1835.36569-.011539 3.0474c.0016422.78594.63212 1.2375 1.2839 1.2647l1.4031-.01522.49205-3.5655z" fill="url(#b)"/><path d="m34.389 2.0256 2.653-.86194c-.10539-.82869-.6792-1.1252-1.4787-1.1421-.20536-.0043395-.37419-.01602-.59203-.019672-.21784-.0036886-.71487-.00035801-.71487-.00035801-.50121.097262-.89355.38179-1.1678.84836z" fill="url(#c)"/></g><rect fill="url(#d)" fill-rule="evenodd" height="12.812" ry=".97192" stroke="url(#e)" stroke-width=".26459" width="32.55" x="2.246" y=".95721"/><path d="m4.482 7.7355h2.4519v2.8124h3.065v-2.8147h2.4521l-3.9845-3.4309z" fill="none" stroke="#333" stroke-width=".77424"/></svg>
src/main/resources/images/key/up/long.svg
-<svg height="60" viewBox="0 0 37.042 15.875" width="140" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="97.58" x2="128.18" y1="202.35" y2="202.35"><stop offset="0" stop-color="#fafafa"/><stop offset="1" stop-color="#f1f1f1"/></linearGradient><g fill="#e5e5e5" fill-rule="evenodd" stroke-width=".36327"><path d="m.84701 0h33.741c.46924 0 .84701.37434.84701.83932v10.724h-35.423l-.011539-10.724c-.0005474-.46498.37776-.83932.847-.83932z"/><path d="m2.5208 13.795h31.832v2.0735h-31.832z"/><path d="m32.91 1.1636h4.1317l.000004 10.408h-4.1317z"/><path d="m33.878 11.228 3.1637.34396-.000004 3.0387c-.0015.78594-.63212 1.2375-1.2839 1.2647l-1.4053-.007-1.5509-3.5889z"/><path d="m2.195 11.197-2.1835.36569-.011539 3.0474c.0016422.78594.63212 1.2375 1.2839 1.2647l1.4031-.01522.49205-3.5655z"/><path d="m34.389 2.0256 2.653-.86194c-.10539-.82869-.6792-1.1252-1.4787-1.1421-.20536-.0043395-.37419-.01602-.59203-.019672-.21784-.0036886-.71487-.00035801-.71487-.00035801-.50121.097262-.89355.38179-1.1678.84836z"/></g><rect fill="#f8f8f8" fill-rule="evenodd" height="12.812" ry=".97192" stroke="url(#a)" stroke-width=".26459" width="32.55" x="2.246" y=".95721"/><path d="m4.3714 7.7022h2.4614v2.8001h3.0769v-2.8024h2.4616l-4-3.4159z" fill="none" stroke="#e5e5e5" stroke-width=".77404"/></svg>
+<svg height="60" viewBox="0 0 37.042 15.875" width="140" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(.36493 0 0 .36162 -33.344 -67.568)" gradientUnits="userSpaceOnUse" x1="97.58" x2="128.18" y1="202.35" y2="202.35"><stop offset="0" stop-color="#fafafa"/><stop offset="1" stop-color="#f1f1f1"/></linearGradient><g fill="#e5e5e5" fill-rule="evenodd" stroke-width=".36327"><path d="m.84701 0h33.741c.46924 0 .84701.37434.84701.83932v10.724h-35.423l-.011539-10.724c-.0005474-.46498.37776-.83932.847-.83932z"/><path d="m2.5208 13.795h31.832v2.0735h-31.832z"/><path d="m32.91 1.1636h4.1317l.000004 10.408h-4.1317z"/><path d="m33.878 11.228 3.1637.34396-.000004 3.0387c-.0015.78594-.63212 1.2375-1.2839 1.2647l-1.4053-.007-1.5509-3.5889z"/><path d="m2.195 11.197-2.1835.36569-.011539 3.0474c.0016422.78594.63212 1.2375 1.2839 1.2647l1.4031-.01522.49205-3.5655z"/><path d="m34.389 2.0256 2.653-.86194c-.10539-.82869-.6792-1.1252-1.4787-1.1421-.20536-.0043395-.37419-.01602-.59203-.019672-.21784-.0036886-.71487-.00035801-.71487-.00035801-.50121.097262-.89355.38179-1.1678.84836z"/></g><rect fill="#f8f8f8" fill-rule="evenodd" height="12.812" ry=".97192" stroke="url(#a)" stroke-width=".26459" width="32.55" x="2.246" y=".95721"/><path d="m4.482 7.7355h2.4519v2.8124h3.065v-2.8147h2.4521l-3.9845-3.4309z" fill="none" stroke="#e5e5e5" stroke-width=".77424"/></svg>
Delta 144 lines added, 83 lines removed, 61-line increase