From f01534c8c611621905b7ea7d46f6e258cbcd640e Mon Sep 17 00:00:00 2001 From: vito Date: Tue, 1 Sep 2020 12:00:09 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-38632=E3=80=90=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=88=A0=E9=99=A4=E3=80=91=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E5=90=AF=E5=8A=A8=E9=A1=B5=20=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E7=94=BB=E9=9D=A2=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fr/start/fx/FastGifImage.java | 208 ------------------ .../com/fr/start/fx/PrismImageLoader2.java | 208 ------------------ .../main/java/com/fr/start/fx/SplashFx.java | 59 ----- .../java/com/fr/start/fx/SplashFxWindow.java | 194 ---------------- .../main/java/com/fr/start/jni/SplashJNI.java | 69 ------ .../main/java/com/fr/start/jni/SplashMac.java | 100 --------- .../resources/com/fr/start/jni/splash.dylib | Bin 57200 -> 0 bytes 7 files changed, 838 deletions(-) delete mode 100644 designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java delete mode 100644 designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java delete mode 100644 designer-realize/src/main/java/com/fr/start/fx/SplashFx.java delete mode 100644 designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java delete mode 100644 designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java delete mode 100644 designer-realize/src/main/java/com/fr/start/jni/SplashMac.java delete mode 100755 designer-realize/src/main/resources/com/fr/start/jni/splash.dylib diff --git a/designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java b/designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java deleted file mode 100644 index 9eb3ecef2..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.fr.start.fx; - -import com.sun.imageio.plugins.gif.GIFImageReader; -import com.sun.imageio.plugins.gif.GIFImageReaderSpi; -import com.sun.javafx.tk.ImageLoader; -import com.sun.javafx.tk.PlatformImage; -import javafx.animation.KeyFrame; -import javafx.animation.Timeline; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.scene.image.WritableImage; -import javafx.util.Duration; - -import javax.imageio.stream.FileImageInputStream; -import java.io.File; -import java.lang.ref.WeakReference; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.regex.Pattern; - -/** - * 边加载边播放的gif加载器 - * - * @author daniel - */ -public class FastGifImage extends WritableImage { - private String url; - private int gifCount; - - public FastGifImage(String url, int w, int h) { - super(w, h); - this.url = validateUrl(url); - seekCount(); - initialize(); - } - - /** - * 给出gif帧数,加快加载速度 - * - * @param url gif url - * @param gifCount gif帧数 - * @param w 宽 - * @param h 高 - */ - public FastGifImage(String url, int gifCount, int w, int h) { - super(w, h); - this.url = validateUrl(url); - this.gifCount = gifCount; - initialize(); - } - - private void seekCount() { - try { - GIFImageReaderSpi spi = new GIFImageReaderSpi(); - GIFImageReader gifReader = (GIFImageReader) spi.createReaderInstance(); - gifReader.setInput(new FileImageInputStream(new File(new URI(url)))); - gifCount = gifReader.getNumImages(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static final Pattern URL_QUICKMATCH = Pattern.compile("^\\p{Alpha}[\\p{Alnum}+.-]*:.*$"); - - private static String validateUrl(final String url) { - if (url == null) { - throw new NullPointerException("URL must not be null"); - } - - if (url.trim().isEmpty()) { - throw new IllegalArgumentException("URL must not be empty"); - } - - try { - if (!URL_QUICKMATCH.matcher(url).matches()) { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - URL resource; - if (url.charAt(0) == '/') { - resource = contextClassLoader.getResource(url.substring(1)); - } else { - resource = contextClassLoader.getResource(url); - } - if (resource == null) { - throw new IllegalArgumentException("Invalid URL or resource not found"); - } - return resource.toString(); - } - // Use URL constructor for validation - return new URL(url).toString(); - } catch (final IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid URL" + e.getMessage()); - } catch (final MalformedURLException e) { - throw new IllegalArgumentException("Invalid URL" + e.getMessage()); - } - } - - private void finishImage(ImageLoader loader) { - initializeAnimatedImage(loader); - } - - // Generates the animation Timeline for multiframe images. - private void initializeAnimatedImage(ImageLoader loader) { - - animation = new Animation(this, loader); - animation.start(); - } - - // Support for animated images. - private Animation animation; - - private static final class Animation { - final WeakReference imageRef; - final Timeline timeline; - private ImageLoader loader; - - public Animation(final FastGifImage image, final ImageLoader loader) { - this.loader = loader; - imageRef = new WeakReference(image); - timeline = new Timeline(); - timeline.setCycleCount(Timeline.INDEFINITE); - - final int frameCount = loader.getFrameCount(); - int duration = 0; - - for (int i = 0; i < frameCount; ++i) { - addKeyFrame(i, duration); - duration = duration + loader.getFrameDelay(i); - } - - // Note: we need one extra frame in the timeline to define how long - // the last frame is shown, the wrap around is "instantaneous" - addKeyFrame(0, duration); - } - - public void start() { - timeline.play(); - } - - public void stop() { - timeline.stop(); - loader = null; - } - - private void updateImage(final int frameIndex) { - final FastGifImage image = imageRef.get(); - if (image != null) { - image.setPlatformImagePropertyImpl( - loader.getFrame(frameIndex)); - } else { - timeline.stop(); - } - } - - private void addKeyFrame(final int index, final double duration) { - timeline.getKeyFrames().add( - new KeyFrame(Duration.millis(duration), - new EventHandler() { - @Override - public void handle(Event event) { - updateImage(index); - } - } - )); - } - } - - private static Method method; - - static { - try { - method = FastGifImage.class.getSuperclass().getSuperclass().getDeclaredMethod("platformImagePropertyImpl"); - method.setAccessible(true); - } catch (Exception e) { - - } - } - - private void setPlatformImagePropertyImpl(PlatformImage image) { - try { - Object o = method.invoke(this); - Method method = o.getClass().getDeclaredMethod("set", Object.class); - method.setAccessible(true); - method.invoke(o, image); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - - - private void initialize() { - finishImage(new PrismImageLoader2(url, gifCount, (int) getRequestedWidth(), (int) getRequestedHeight(), isPreserveRatio(), isSmooth())); - } - - /** - * 销毁gif动画 - */ - public void destroy() { - animation.stop(); - } - -} diff --git a/designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java b/designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java deleted file mode 100644 index 4529465c7..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.fr.start.fx; - -import com.fr.concurrent.NamedThreadFactory; -import com.fr.log.FineLoggerFactory; -import com.sun.javafx.iio.ImageFrame; -import com.sun.javafx.iio.ImageLoadListener; -import com.sun.javafx.iio.ImageLoader; -import com.sun.javafx.iio.ImageMetadata; -import com.sun.javafx.iio.ImageStorageException; -import com.sun.javafx.iio.common.ImageTools; -import com.sun.javafx.iio.gif.GIFImageLoaderFactory; -import com.sun.javafx.tk.PlatformImage; -import com.sun.prism.Image; -import com.sun.prism.impl.PrismSettings; - - -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * 边加载边播放的gif加载器 - * - * @author daniel - */ -class PrismImageLoader2 implements com.sun.javafx.tk.ImageLoader { - - private Image[] images; - private int[] delayTimes; - private int width; - private int height; - private int gifCount = 1; - private Exception exception; - - public PrismImageLoader2(final String url, int gifCount, final int width, final int height, - final boolean preserveRatio, final boolean smooth) { - this.gifCount = gifCount; - images = new Image[gifCount]; - delayTimes = new int[gifCount]; - this.width = width; - this.height = height; - ExecutorService es = Executors.newSingleThreadExecutor(new NamedThreadFactory("PrismImageLoader2")); - es.execute(new Runnable() { - @Override - public void run() { - InputStream inputStream = null; - try { - inputStream = ImageTools.createInputStream(url); - loadAll(inputStream, width, height, preserveRatio, smooth); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - }); - es.shutdown(); - } - - @Override - public int getWidth() { - return width; - } - - @Override - public int getHeight() { - return height; - } - - @Override - public int getFrameCount() { - return gifCount; - } - - @Override - @SuppressWarnings("squid:S2142") - public PlatformImage getFrame(int index) { - while (images[index] == null) { - synchronized (this) { - if (images[index] == null) { - try { - this.wait(); - } catch (InterruptedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - } - } - return images[index]; - } - - - @Override - public int getFrameDelay(int index) { -// while (images[0] == null) { -// synchronized (this) { -// if(images[0] == null) { -// try { -// this.wait(); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// } -// } -// return 0; -// } -// return delayTimes[0]; - // 直接使用第一帧的时间 - return 40; - } - - @Override - public int getLoopCount() { - return 0; - } - - @Override - public Exception getException() { - return exception; - } - - - @SuppressWarnings("squid:S244") - private void loadAll(InputStream stream, int w, int h, - boolean preserveRatio, boolean smooth) { - ImageLoadListener listener = new PrismLoadListener(); - - try { - ImageLoader loader = null; - loader = GIFImageLoaderFactory.getInstance().createImageLoader(stream); - loader.addListener(listener); - - for (int i = 0; i < gifCount; i++) { - ImageFrame imageFrame = loader.load(i, w, h, preserveRatio, smooth); - images[i] = convert(imageFrame); - synchronized (this) { - notifyAll(); - } - } - } catch (ImageStorageException e) { - handleException(e); - } catch (Exception e) { - handleException(e); - } - } - - private void handleException(final ImageStorageException isException) { - // unwrap ImageStorageException if possible - final Throwable exceptionCause = isException.getCause(); - if (exceptionCause instanceof Exception) { - handleException((Exception) exceptionCause); - } else { - handleException((Exception) isException); - } - } - - private void handleException(final Exception exception) { - if (PrismSettings.verbose) { - exception.printStackTrace(System.err); - } - this.exception = exception; - } - - private Image convert(ImageFrame imgFrames) { - ImageFrame frame = imgFrames; - Image image = Image.convertImageFrame(frame); - ImageMetadata metadata = frame.getMetadata(); - if (metadata != null) { - Integer delay = metadata.delayTime; - if (delay != null) { - delayTimes[0] = delay.intValue(); - } - } - return image; - } - - - private class PrismLoadListener implements ImageLoadListener { - @Override - public void imageLoadWarning(ImageLoader loader, String message) { - - } - - @Override - public void imageLoadProgress(ImageLoader loader, - float percentageComplete) { - // progress only matters when backgroundLoading=true, but - // currently we are relying on AbstractRemoteResource for tracking - // progress of the InputStream, so there's no need to implement - // this for now; eventually though we might want to consider - // moving away from AbstractRemoteResource and instead use - // the built-in support for progress in the javafx-iio library... - } - - @Override - public void imageLoadMetaData(ImageLoader loader, ImageMetadata metadata) { - // We currently have no need to listen for ImageMetadata ready. - } - } - -} diff --git a/designer-realize/src/main/java/com/fr/start/fx/SplashFx.java b/designer-realize/src/main/java/com/fr/start/fx/SplashFx.java deleted file mode 100644 index f5c64bf79..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/SplashFx.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.fr.start.fx; - -import com.fr.concurrent.NamedThreadFactory; -import com.fr.design.mainframe.DesignerContext; -import com.fr.start.SplashFxActionListener; -import com.fr.start.SplashStrategy; -import javafx.application.Application; -import javafx.application.Platform; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * JavaFx方式启动启动动画。这种方式在mac下与 - * swing一起启动会会出现线程死锁,jvm等问题, - * 所以这个方式仅用于windows上。 - * - * @author vito - * @date 2018/6/4 - * @see com.fr.start.jni.SplashMac - */ -public class SplashFx implements SplashStrategy { - - private SplashFxWindow fxWindow; - private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor(new NamedThreadFactory("SplashFx")); - - @Override - public void show() { - Platform.setImplicitExit(false); - SERVICE.execute(new Runnable() { - @Override - public void run() { - Application.launch(SplashFxWindow.class); - } - }); - fxWindow = SplashFxWindow.waitForStartUpTest(); - fxWindow.addSplashActionListener(new SplashFxActionListener() { - @Override - public void splashClose() { - DesignerContext.getDesignerFrame().setVisible(true); - } - }); - } - - @Override - public void hide() { - fxWindow.close(); - } - - @Override - public void updateModuleLog(final String text) { - fxWindow.updateModuleInfo(text); - } - - @Override - public void updateThanksLog(final String text) { - fxWindow.updateThanks(text); - } -} diff --git a/designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java b/designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java deleted file mode 100644 index 00ad51293..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.fr.start.fx; - -import com.fr.log.FineLoggerFactory; -import com.fr.stable.OperatingSystem; -import com.fr.start.SplashContext; -import com.fr.start.SplashFxActionListener; -import javafx.application.Application; -import javafx.application.Platform; -import javafx.geometry.Rectangle2D; -import javafx.scene.Scene; -import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import javafx.stage.Screen; -import javafx.stage.Stage; -import javafx.stage.StageStyle; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; - - -/** - * JavaFx启动动画窗口 - * - * @author vito - */ -public class SplashFxWindow extends Application { - - private static final String ARIAL_FONT_NAME = "Arial"; - private static final String PF_FONT_NAME = "PingFang"; - private static final String YAHEI_FONT_NAME = "Microsoft YaHei"; - private static final int MODULE_INFO_LEFT_MARGIN = 36; - private static final int MODULE_INFO_BOTTOM_MARGIN = 28; - private static final int THINKS_BOTTOM_RIGHT = 35; - private static final int THINKS_BOTTOM_MARGIN = 27; - private static final int WINDOW_WIDTH = 640; - private static final int WINDOW_HEIGHT = 360; - private static final int FONT = 12; - private static final int FRAME_COUNT = 315; - private static final String THINKS_COLOR = "#82b1ce"; - - private static final CountDownLatch LATCH = new CountDownLatch(1); - private static SplashFxWindow app = null; - - private Text moduleInfo; - private Text thanks; - private FastGifImage image; - private List listeners = new ArrayList(); - - /** - * 获取当前运行实例。黑科技 - * - * @return 运行实例 - */ - @SuppressWarnings("squid:S2142") - public static SplashFxWindow waitForStartUpTest() { - try { - LATCH.await(); - } catch (InterruptedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return app; - } - - private static void setApp(SplashFxWindow window) { - app = window; - LATCH.countDown(); - } - - public SplashFxWindow() { - setApp(this); - } - - @Override - public void start(Stage primaryStage) { - AnchorPane root = new AnchorPane(); - primaryStage.initStyle(StageStyle.TRANSPARENT); - image = new FastGifImage(SplashContext.SPLASH_PATH, FRAME_COUNT, WINDOW_WIDTH, WINDOW_HEIGHT); - - ImageView gif = new ImageView(image); - - AnchorPane.setBottomAnchor(gif, 0d); - AnchorPane.setTopAnchor(gif, 0d); - AnchorPane.setLeftAnchor(gif, 0d); - AnchorPane.setRightAnchor(gif, 0d); - Font font; - if (OperatingSystem.isWindows()) { - font = new Font(YAHEI_FONT_NAME, FONT); - } else if (OperatingSystem.isMacOS()) { - font = new Font(PF_FONT_NAME, FONT); - } else { - font = new Font(ARIAL_FONT_NAME, FONT); - } - - moduleInfo = new Text(); - moduleInfo.setFont(font); - moduleInfo.setFill(Color.WHITE); - AnchorPane.setLeftAnchor(moduleInfo,(double) MODULE_INFO_LEFT_MARGIN); - AnchorPane.setBottomAnchor(moduleInfo,(double) MODULE_INFO_BOTTOM_MARGIN); - thanks = new Text(); - thanks.setFont(font); - thanks.setFill(Color.valueOf(THINKS_COLOR)); - AnchorPane.setRightAnchor(thanks, (double) THINKS_BOTTOM_RIGHT); - AnchorPane.setBottomAnchor(thanks, (double) THINKS_BOTTOM_MARGIN); - - root.getChildren().add(gif); - root.getChildren().add(moduleInfo); - root.getChildren().add(thanks); - - primaryStage.setWidth(WINDOW_WIDTH); - primaryStage.setHeight(WINDOW_HEIGHT); - primaryStage.setScene(new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT, null)); - setWindowCenter(primaryStage); - primaryStage.show(); - } - - public void close() { - Platform.runLater(new Runnable() { - @Override - public void run() { - try { - ((Stage) moduleInfo.getScene().getWindow()).close(); - image.destroy(); - fireSplashClose(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - }); - } - - /** - * 设置窗口居中 - * - * @param stage 窗口 - */ - private void setWindowCenter(Stage stage) { - Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds(); - stage.setX(primaryScreenBounds.getMinX() + (primaryScreenBounds.getWidth() - stage.getWidth()) / 2.0); - stage.setY(primaryScreenBounds.getMinY() + (primaryScreenBounds.getHeight() - stage.getHeight()) / 2.0); - } - - /** - * 更新模块信息 - * - * @param s 文字 - */ - public void updateModuleInfo(final String s) { - Platform.runLater(new Runnable() { - @Override - public void run() { - if (moduleInfo != null) { - moduleInfo.setText(s); - } - } - }); - - } - - /** - * 更新欢迎信息 - * - * @param s 文字 - */ - public void updateThanks(final String s) { - Platform.runLater(new Runnable() { - @Override - public void run() { - if (thanks != null) { - thanks.setText(s); - } - } - }); - - } - - /** - * 添加一个动画状态监听 - * - * @param listener - */ - public void addSplashActionListener(SplashFxActionListener listener) { - listeners.add(listener); - } - - public void fireSplashClose() { - for (SplashFxActionListener listener : listeners) { - listener.splashClose(); - } - } -} diff --git a/designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java b/designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java deleted file mode 100644 index e71a44ca2..000000000 --- a/designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.fr.start.jni; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; - -/** - * Splash JNI调用。jni类改名或者移包之后 - * 必须重新编译动态库 - * - * @author vito - * @date 2018/6/4 - */ -public class SplashJNI { - - static { - try { - System.setProperty("java.library.path", "."); - System.loadLibrary("splash"); - } catch (UnsatisfiedLinkError e) { - loadLibraryFromJar("/com/fr/start/jni/splash.dylib"); - } - } - - /** - * 显示启动动画窗口 - */ - public native void show(String path); - - /** - * 隐藏启动动画窗口 - */ - public native void hide(); - - /** - * 设置模块加载信息 - */ - public native void updateModuleLog(String text); - - /** - * 设置感谢文字 - */ - public native void updateThanksLog(String text); - - /** - * 从jar中加载动态库 - * - * @param path 路径,如/com/a/b - * @throws UnsatisfiedLinkError 没有找到合适的动态库 - */ - private static void loadLibraryFromJar(String path) throws UnsatisfiedLinkError { - try (InputStream inputStream = SplashJNI.class.getResourceAsStream(path)) { - File tempLib = File.createTempFile(path, ""); - - byte[] buffer = new byte[1024]; - int read = -1; - - try (FileOutputStream fileOutputStream = new FileOutputStream(tempLib)) { - while ((read = inputStream.read(buffer)) != -1) { - fileOutputStream.write(buffer, 0, read); - } - } - - System.load(tempLib.getAbsolutePath()); - } catch (Exception e) { - throw new UnsatisfiedLinkError("Unable to open " + path + " from jar file."); - } - } -} diff --git a/designer-realize/src/main/java/com/fr/start/jni/SplashMac.java b/designer-realize/src/main/java/com/fr/start/jni/SplashMac.java deleted file mode 100644 index 6d2a47a2e..000000000 --- a/designer-realize/src/main/java/com/fr/start/jni/SplashMac.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.fr.start.jni; - -import com.fr.log.FineLoggerFactory; -import com.fr.stable.ProductConstants; -import com.fr.stable.StableUtils; -import com.fr.stable.StringUtils; -import com.fr.start.SplashContext; -import com.fr.start.SplashStrategy; - -import javax.swing.JFrame; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * mac上使用jni方式绘制gif。不使用javafx有两个原因: - * 1.mac上javafx和swing同时启动会导致卡死; - * 2.platform.exit会导致设计器崩溃 - * - * @author vito - * @see com.fr.start.fx.SplashFx - */ -public class SplashMac implements SplashStrategy { - - - private SplashJNI jni; - private static final int EXILE = 10000; - - public SplashMac() { - jni = new SplashJNI(); - } - - /** - * 将jar中的资源拷贝到缓存文件夹 - * - * @return 路径 - */ - private static String loadResFromJar() { - File tempLib = null; - try (InputStream inputStream = SplashContext.class.getResourceAsStream(SplashContext.SPLASH_PATH)) { - if (inputStream == null) { - FineLoggerFactory.getLogger().error("Unable to copy " + SplashContext.SPLASH_PATH + " from jar file."); - return StringUtils.EMPTY; - } - tempLib = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), SplashContext.SPLASH_CACHE_NAME)); - byte[] buffer = new byte[1024]; - int read = -1; - try (FileOutputStream fileOutputStream = new FileOutputStream(tempLib)) { - while ((read = inputStream.read(buffer)) != -1) { - fileOutputStream.write(buffer, 0, read); - } - } - return tempLib.getAbsolutePath(); - } catch (IOException e) { - if (tempLib != null) { - tempLib.deleteOnExit(); - } - // 直接抛异常 - throw new RuntimeException("Unable to copy " + SplashContext.SPLASH_PATH + " from jar file."); - } - } - - @Override - public void show() { - if (jni != null) { - // mac下安装版模糊的hack - JFrame jFrame = new JFrame(); - jFrame.setLocation(EXILE, EXILE); - jFrame.setVisible(true); - jFrame.setVisible(false); - File splash = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), SplashContext.SPLASH_CACHE_NAME)); - String path = splash.exists() ? splash.getAbsolutePath() : loadResFromJar(); - jni.show(path); - } - } - - @Override - public void hide() { - if (jni != null) { - jni.hide(); - jni = null; - } - } - - @Override - public void updateModuleLog(String text) { - if (jni != null) { - jni.updateModuleLog(text); - } - - } - - @Override - public void updateThanksLog(String text) { - if (jni != null) { - jni.updateThanksLog(text); - } - } -} diff --git a/designer-realize/src/main/resources/com/fr/start/jni/splash.dylib b/designer-realize/src/main/resources/com/fr/start/jni/splash.dylib deleted file mode 100755 index 6ae677da37199ce7ebe825dbb5590452bdb081dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57200 zcmeHwd3+Q_`gc!~fdImUBP=3l5D-v~Odybekqk+&Mc6UrxT9-y??x)&+naq z?yBdgr>dTM>UyfX^V#X|&vuj~L#!l89dPx;)p&^{)k_J8Nz$dbN!us;f%jU_J z^FSgvPQ=>_?DmR++Y9aGPH&0JQSNNh9w&vozY8HMtjdZgE0987VVT3@A%XhxeQf0^ zZxjMl_yY2%eBSEHw&lC>2A*=B5TL^6mRIQUx=UU21%tkP_Xv3(lHuZ~!W`1I4Ul&G z{K7)Jv#QWp>9u$o1ncB!i--1Q<4S3{W4@D2Szq53y7CcxK08+Rrw)F4c`JpyOi?I; zFQR-NXPMhsjNx7{FEEQ&CruQJV68lKDODAWQIwDAk0k2lCC%aT)Iu6Wrav^VpNJa4Z<%LAGD=+OPAxMk|1fO4CVMTd)g-fJrV=rkpbBd}zg0%8P zHfnODFYts{8Ex$^Q^>2)bPDY}u9rvSyo}3kw^^r7$;r0P6j{v^VNE1l`8y8NxTlrX z6>u7^J|R3&4bmu|$33d7qR>$`s;sntE~j&3Q8hx4@w-xzYLY23kC#J6s9ku-MUs?+ zPE%4UNi85zwJ49q+a>8!gq78jwDU4a>Vmjx)1)7|sEl{uQmce$n_uN(6rc@Ok|2`h z;2AZ!!smj~l~%Y$7OU7%vz=}aFrHCa8am{Xd{xg( zzO)}0RnJ_*G=h$_Xtm7Kk)BC+lrFAQBN`|&UEwv?j5Ld6`h1Kn`{VTdyh+1< zb2Rzf-uXV%e}r_N`dcb1r<8izuREtf9?31y$d#C0A3LAitO~dD{JOP_isXU(t8h{K zCd0nwAsi-PvN!tm$3^tKM`4#Y5GMMIY9OkCs0N}Mh-x6Jf&cd!m?iuFZMo4h+cL{C zGhe>@@JOU*{{~1i2d@WX){+t$B$=HyEsFLcnNK!DdH^XlZRE;3|2DyHhw~wqO z+Ch{X-cJYygR*~5U@EAGx|?onHVvy!0uBKu?F}aGpCC!cObHBs%rwXN$SA3Xl}+|*$jE{?)*Ul-Zq4l6; zHAO8m^7Aay1NPyNP`fe7>ffAOA2ijC#u5%HTRw?`)SEI%=-_Y1gFpDWO&O5~gskMQ zmX%peHYI0;tjt|0`#0PCN2brnx8#9|3)_Um!zr;JB|T>I`?e8D$spe)NCuD?;zE+B zg_P8T6G_qu+5Z(wl=>~;wY2Gw{d=wcJrKW~i~o^YQAvFsbk5m~7|Ms@wh)3zdq*n` zb?SxML69Z*4s<|Rl%B9^>CX81>m zY*SboG*22KsaUDO>m*65I$p$KtcYM?6=r3#DXEuntj&L%)n#+w9c)Q>f_RY3J6J7H zOR5XgyvnGA7{5b)=V2@eF>X3PV|s}3#Yje*|4{Jn5t(-btJVJzTE76zjym6o6zD6) z1+YC)lY>}%Tm57;#UR@JKfr20LL-o{AGkzi#HEaQL?n7wO_b4{3r+!<`s|Hc1jobR z;0n5erBqGGzgJfJ_e;Zg0O>3Xn5ioEwvgDh&?<^_C?izPNg;uIfDGHDe=iK_<8j0X z&BJm?|43RAPTEmTx?~#&zX3tpywFEZ6Acr$T|>%I!|wG}FcnzYpMW-X^F=f$Qa z6N6hLblQQJ@lP1msM1OgkXAQTr$3bsvX9HLz^mf*hW5af48_Lwk>;`3j zQsmXv&IU#@-f>RG(?cR8-gHjJ?U9UW=VV+7Ms8(iNVQ68B3Q}Fj4(f84s~1@3<~sL zF^q>=0OrsYzG98Bg*w@^kl@!Kn41@pZ$fe*c7#^!DxKI>sqKqBiR~vZ?@V6a7m<+4 zTMj!x*j0pyBJ5A0$nZU+g<11@%+h6;6VA};|2m>4*70;GeI^pABPbKvX2_T$@=$!+ z$jp^gCmSZi1Cp#P!Kf>&9Y9MkaVy;SHvdWa?u|4P-(tDdGS_mO#XfgKXri8(Z&NZB zpk*+eok^!!V5)u+$*4NY;A$oSeUS}ZO6qeg&&|AaBm=Deb9R~6$drS2UjrBNCK6Nmx#F8_#^`Q%?%DdGg^|g zC5MgN%_Qvd-h$#csKwt6K1`n|{#wK^`i47B&%uPCDeMQv4bo|-8>ycKE84~q{DLJo z8ZM|B(`DU3leJsT+7ZfnqCV^8a9{DPy}GOiU0l{!UeLTRD{&op1In=(+gW>jF}F1n z(zzCmAL*IiQJF3iO!;}T{}-tENg^2bnvVwzRJhpw_W)r&4h3M*5P!?u)`J6u)Y`+z zvLC~wiH4j_!Qabp3(88@gJuK`zMZna+Zwb{v+SQ5FE@0Bl2O&E35dos>zLX{_D@bi zj@ywS&<|3PL2`r{@)EU@YLwKQF%!VFegQX`k$-dGW=iAV985d`99niB0;_WEATXzb z*}MaMXvODP`ixgukdGWwuK-oZ=*?tMV*LW~SVOJ|%lj3x2J4Dy!v_buiHg~f zI2Ta?{3ikj2Vn5&!gZc8jF)>WlEP54z@qjr(zQ-;DCa2@0P2Y0$?illRQD1jll|*O zX-lpoh)R1Gku{}djl+A<-~b$pYRPsZP9@6=m5kQn?H8bm7vOFdq@Ko5ivlPR5H7%X z5W@=)d!7Q!*A(CuQGm~qRMoJ}0JZ|P8OO1BmVB4U4H@so!3I`?1@UIg1p%371hu@4 zaY9Bcp`|)x&l+Tn0W#2;1C=brcDW((rH(8Gj51KmMfynOe<)5PSjK!+ zawU3C$mdJkzp_DU zZy=wg=>Ky+V)&Az_dv$GNi2q-N12RuvcKy<-fQkhGU{*r7$L;}q2PCh_IRW)f~LT=g84q+XaV3) z&E@%ifTd<&2@}Efypi;*r1lmh_$e9s*0FX%Lr;P-py7b#+_gQ zgpC(ij5|2=J5KwALugN;Z348(xEXiDp%=xpvy3>D)CHJ0FztMT9>NK!4vtwXFkzoe z?cpk`{~xm7SCg$QPROZ0ZmOF}{m;LoQEsp&nVYeTS()SiS@zFuVZe&o377h0Tf?34 zw1H|!J%g1(ARg6)&IWVTQ9}I(?ONaLyIfYX`pB_4E97gkhLWs9m&gkCMb`l9&sm{l z#mR;Zmf$D8mCRF7ze`qpEvC9{7}?FuD313Qur+7l=I%=Y{4m;HP%=l8YLUU#Xf z{wHc6CAURxm@X@pOt~ShMqalsPHxCH$lzrjp!98~dp~9kIcs^%9hn_X^($GboaM5T zIaFR3h(&oCO?3~2uyT?do4Z2xH<0T{$;<|QWsZ42w7JsK5Eq9Go0Pb_C**wYnVnnz zy>~jxQps&r`WfWdxvMQ7qP$X$`M7o60Wjy(+@M^GHQb(ntuJf4t~vg*mf+^x^ds)C z5B1^<*~xHRvHWiE$9V&tk7zyRnM;j%LdNTm24$K5R7!qeXa$Wc7b$^<&|UMQQ4%U1uuq)Amhr}@WR%WXK+ZL*b;I1;rb5$qUqcQ5Nxx6Av5rS_wamfC-x zwE0ijhPA@G9cvDnR{bQSkE}b0K6$$KfXUnQ#2z_)J0_y^t-t%D99$pVQtN?dl?y}`Ex0e#2+ZAI zdw8hTe;n;VYAUD7zC~q*)=~Vky+}Rw{BTx`{>N%GoI)&sT!5udG8$60DOL*w6_w8buIffBP# ztNxYiKVV&VByL*6@DrBW{U+}unp5DFn1X57(vUp}c9zp@IkDTSEJ1cbZztGYFmdoe zsG|0xcuR1j4_=R)W}D$?ZbR8-jJ-Llm-Wf@|A4l6`Vh^RC{3oO>ZYaFv2hnQXzs~s z5LObrLYPTg|0DVa+VdkU957O?Lbs=en%kO!G-5=2i_`ufXyAUCW0ndG);UUQEpVug z7r5ZxRT$>#-^nZiP8=cbcAj{OHt}Shc$}J;!R;mP&l7hOiPbHm|0gmfWt=sAj~BbZ z)Z;WGD1-T~6z-ImdCCNu2Wr&bgLz{)2PA!#UsOGS33qWPBNSL+h2o>S=XOhI$7&U?9Ca zM)$6A`c7|mTGT&~fD&Padc@p(D5l9^TGh;rm@VsriPMk-Y;#-BbmP4wn3%1iS_O(s zGaqvTT%^gMS^S%5#o8+yrm9Q~Yyg+F7Tq}bvF`_3!G;ziTF)U;vr+O44NuKTf>8`p z3cMO{ss3`1OmWs9B?A<@-F;+v5Y|HAebkoe3+ zO6=E0Vo{_-rz+8QK8cv4X&$Bh^46~5TH|aOwWd8QO+z^NP3_IasWlA_roF5Rg*8c2 z4w~XqR(s6;zmnuiRWgpN4#2gGU3@U{BN`zf99xsrHJIF>Pu?`@92*?`5SbfmE)^G< zkz9K?4VJ|l4z7>!5D94?W5|MwX(m#W(@sfsGx3|52ais=MSgQvAWzQG#5i*3j1~wi z9I$pb)zwMVy3S_IQkXxC|H2G`(H{r8sYemTs8>zN6ys@5zyZJyfx1hG3I4$)E3k)Z zviT3P9G0{&Q(BLz1Gc3f@^+>QX{@#>$XQvk?NCQl=5fl9+oLkK zg|*K8wD_g<_gUyDjhccl>4SrB#y&7|5peh6rKk%U8l~NhEupMXO}2%XJXWROAgeNS z5Y|2aunzc}rFMxVRmbHj<(U3FNiw?4fR@@cplG_cDt8Tv$IR*LVmY28#hB`P#ZXb+ zokP>0|54f*$^QC01Xd+`5K`wfQ-r3@)f7oUq{*tpAx9eo`E#N79H=W+R;B>tTQh${ z6`NJFh`WaEU;Q~t5t6({G~y>{=3t@=wZU4A+#IB!Ks@x%0H`MLOBWCoUmtX8EMlPh zfC4f)GFCUHI-`M-yg`o<$g4Xdy;MVo&+k+DtpjjS@dj1MI^ZL+;k#JE=G;zq4N9_g zT971vpe{zN0~aOLUMJ=HPmp#N#UmYwv?@8t7}#?Cn@n|?$SGTy8keIu1>vX88atl6jY9Z9GDoe~*8cTzglac*%RIV(XK{9D0BMw)RxeV#?lON&h0- zH0hY(7diN;?+Z(COU|%wvi)1K4L@2=?8))}Xc@4@yhT=+Xykt=MoBaM>6EO@Ohc>f z@OI2Lbf!`S*JY=F>HgQDB3kWO{nS!e>QDq79u0&D20Ln)+?7^8TFUB=8w5n7>_;Og zXbeBx2iU_R1S4-Yg*Tg@8WIb@VCx#x2j#QWz@n z`tsDYnr;v`IoYD*#AO>={FCEyVsqoOae%?v@JL{NEU5k1s z5!lOFlwofRWAhPZHp?884<(@m8WPt6iE=HYEdpA4M<)t{fvV0xE5#MD(k#tm=R+f z&fth}ATSi=!cc@V5!9DK8`VSyZT@cp?;~UMnWWlp4AxG$NmgYlkJ`|b5i;4h$(>~I zJr1M3@fxMY1l$uLHp(4X344OVQeuVrGlm>Y$~}~*I-J1HB)GBY$5 z(|~^#r&V}i4-(mK?kdWmBP7!{3eiolYTAEvBL#*hU~0$^6db$^IjVY8h5i|>s};H$ zl7!HO7bP^K9ig}BgjR%w_PZ#dM=|#3OWH{%^s2DX%@|!ST>TgHLfM!Qc#93LVYR*o zVL}5H7bQ1e$PFe=M~n^KnXEXrKTV)_$yYIpUI4-BM=E4Ka^D`xh`n2!FnDKH2p7ud2< z;+zT2IQJ)(;~nF?z2w#5;dye>-DrwF=UPgTrBVJ?<@%wtl^-HwqVo>;D;tn8jCxxz z_M8Z8#va7~B{2mz$m#Km4}>i@)DzePb`Xb!55#2;$|QNyYO7EkE5<@49+mk_Zn!lb zgX3PD(0(2mhvKux8%8U+^cWA;3xOMv6Db1O{t&ny033o$TK0shIQLqfuR7baymd#m zM=|iQ?tH0S+dNclTUGh3htN;66;E2WQh2Rx*uSg|Q#;BZlDeqI@_^4|!)9)I>)DV4 zPYsQ;np@a7%4{;hC02iM#D z+ikHQw(YRBO0CB{|~PO92PX5nVS zYNx@to^~4z{a>KKl(Q4g!M7P^$Q8btG-A80|;Sk@VI%rIFZ=o0{sF{l&g&?Qy zIF*%VDVmpP%DV<}_(|&TW6T*lum%d8qFj`WduhvyrCE1#Fff}?GyrE*0&Cu3-hw_H zm<%lWeCqf6#@hT#A_VUM4XT@jz6W})Df>H!98HNSDLI1TNhZ!7Da-p2&-H&tjvh?3 zG_WVDMz+D)V26Wj?oJy07ZG1WQAhaRQwvPtqnAJ-&+c-$VF}t|7F_kz2@V7vLA~nW z2lBxv58=SZ_!Hah;&Qza>s4|P525ZSya^R}Tg{ai^lv%@Eb_}sM@D|L;rVMO7EH<+? zr6ZYITC%rjGg%tiB*vP4)RSSxYQ5`xYB19WIKtUcbxm&JS6RoipU8;wCRu~c;9Jn# z*>9-4+ETlITee{vqF2}yO6>kbUT!sjqa#}N*>%8}9&1i&ffKZu+X{c8AvA$sN?JXL z+*#}HVI#ua*53nx-b53s#=_W+j8-DFhQxSes{11fEl)7^LKB+m9tZFNeOG`)K1UQX zth*_qq*i08#_SHnU}7xlMr-GWVgs$T6Ce-s5Y21z!8;4Q@Kf$V`&w3$ts)KfdRV5w zX9+8M0|y*n8wuARL!=Hz0+kbE3>_2@f%e_Oz@tn6UulGPHX8!4L@7A-^T7c*!^>M z|AO6jvin!;zMI{t{=vcf*!^2}-_Py`*ge4R2ig5FyB}fqqwIc+-G65H>Y}EDfTMG8Y#AdVy{!|F^X-X*!>jymSXo% zY#O>>YZb+cDCVNr6BH|=7@fwp-b}GCDMoAik{>8GnPRlGYQ2_XS5hp6Vwn^hN-+n; zE~gkRYFc|y>`{t!rWkDxS|y5oMzQ1Q#wDjIMjg7OCoHw~TZ++`+PafslPLBn#crb5 zMvC1iq?v85EdpJKnI*dHk7rPyl}yPaaR zKWd#vu~@3_Y>M@zn2lmXC^m^=6DXEOu{$X?l48p!Hi%-+Q>pq=?0t$QQ0#k(b)eW8 zikJ-2tl;IWIP!jfT>3GTG^oqo@ zOP!0sR8*AjD_F$hM02>Z-Hycq<*~ZF6*fmTNz-NRnN~cxvt&Xms3=V z&tZt{^1)iDg6sv_$xz3%;{4J(cqs@RFBMjlRk%r6HVSjJ0> ziGjtbEL2KC5D+V8il)pdVc|1S>iN_{;|t1s+FUGUrSo0oXr!>}n4a<+-jeZBxnqHI zinH3{Dw^gla=ItGd6CO1JWeV@KKrW3YzK*yJS7!qsFKnmr{t@|JHgJ}iXvZ`(^df$ zbHvONhiid{Ax0KfRoRQ2_$-O9&?~X;*$6d<<0%m7a660e9&K4^A$!S~wN;@PZ{X7_ z$9ec_Lt!;?X2l>K&YC$njTZ_g!}*-n`K}83_{lVHiPH^PXymdAN0H=mE|!YiFkK1n z9HXTyUaPCfS>+@{^Ax&EE1?q9aT+6zceF$0=_XgWp`wUn5dx`+eJ(GVu#hFWot0&d zLMI1BzT+38{3-(%z$I%-QQS7KHbrd9KOPyDS1c0wsZ!leFICDKIp*A%GLy%rWtzuIi_BvwDrJUIKy%cUQ}aWE z(3R4n%<(GMbV@inMaY<*GDZVIkaoD5nHeEv_*KKF4xb(FT;?!uigW?q6lqaf=EP)a zYQ80GBzYATWfK43iNn!SD|yZ!(B=vG%KGU=pb5P5~ivJ zAu{hQoUYM9h)(@WqcMTkaL#ageQp;UKhKruB3O#r@_48(qgzzqn@>~oXTgkf9WKm% z?mTxz73v4;rjA41Tgn_ikTlBZVuS*W*_SjXhIk-&CqqQ-&YoOHWhKlS1Pu1`tIb+k zxE0KynmLMChIx)suI@rR8$ysc5>L&7(uwY6MeBHkj8K`m&H?6P5aZPdp=LN2`bsfv zXwhXA6$@rnYB5L)U3e=n{Yv&iQUv8Wm3u5@-!u3Q-{6r~dj_M}9Hk<{_?g~3B4tVW9*KBI(oMoI_~fwIAr!fbZuFxF z{Ik;Q1k~fopa}g!ywf-=NfaU81%#M`YZyi7_uuehCm`WqihaXw3_^nO#4h{x27%qX z#2E~d!LWUf(cmz|(lvc(o+QzC=4iEwsMOtp8-4`4vHqrSfaP9+Z=N9h6yZ|{v9`yz zF-A%oSq@U{D;*`n@OViojF${Ip&B?|kNF&7a%ZW-F?i>@bdikrOsi17B_l3_z{DfZq=ak_n}6!Rm(*uGNCNNj2|`$~pJgm?9mV%|js zclDFv`t+9!1(!>)v4f^ao$C3&;Ws;**J61V51$v|>mpnw!e$X}72)S1+#|v{lX&_9 z5tfN?kqB!2?F0&gkK5#ei0rK z;Ykt32zi%?u(t@4M0m9b$B6Jc5y~Q*A;MclSS-Ry5#AxfIuQ;M`F1 z6QOEjLq+7P8+hbPD-YH0MJ3$CVfA}Y%LPo>Ok6l8lj3llos1iP>h}W=!Ouj$xa)a1 zLdbW~V1QpIfmiuo6!^Y6d=k#{=~s_|gUYIwmmzUezkjHHzf8rSE2Q$m?9HXCRq6D!UEq^Ii@~LS_bXkL zLl*hPf`;KtYNU}EznpW>;qqZ}?h)x4MEIr%*NBiFaiyV>{CV{Ir)YOopL6m#UcDdH z!D%x&r6+>++T|-DFKw18;rwBbbC6Xz=ODL1Q~OetUJ?4aQPg)@5@#hk>3OxF-y-Oo zDoHy8zF3D>`Bc0r=cwRU?MRg~N9HlFPL9f_;!leH7%S|klL*I(@LCa05#cQ&oG-#U z5k4itmqhp%5vum7+V38LKPbYpBJ3jUvabk-i!fD$Q$%PN;q4++?OC<=hXnpD5vu)c zhkyejJR-vBLVtxKtP-I*o;)C6bsSO04RxG&Q_$ZQq1vu$JF4x|Nwh~F5ne9BVIsUi zggz0f?YC6Ge-PoDB79eb?~8DY2zQF`YY`q1VHeRK28eK^2xSrGig1nyy&`;Agl~(m zS%mG4$Exl9H=#Pt>(hkrVtj}fVY3*2^!zG3PmBvHe6BD-j3)shPn~D<{40e#l}}Gs z;iI~I4+uS}^f?zf4$Tt@8ZW?a)b;BX7vNXRp~~NR4*r*4dzJjk(O*;pQ4K^j5Y@o{ zryA%!pxH2Q%%s_qZq1sJGp`4pPsyJ&b5g#gGQP6UjO#0t+4Cy&%nJU^n{s_+0{-=> zOv;}$BMU6?l|upHKD~RUecGfOvg}zlOMbq6kUivlo4)X5LSqj>&CQu<33Kq11F0sn zF;je2*jZlbt+p3B3QL?)%|0BfvY(+jHc7{_h&f%Qnw=q@cfb+p6RT-Fq6z?wxx?Bz z?`q;3Ep5D^A&;<{?i_A3l^pW%X%JyAp9UFn-)V4>zCV?q_5P{2a?kvHr>jU(OYC-P z-IFSpdLR;p*_jCk+w)U`(#Ct(*b_}+pN|7Ce23bDGmbKxpV${AOEm!;`Lds(u@`u< zoy87cnRkZIg;O(}PNLlcf+1*tWEcY6vN&ke!Wy6XqzSi;;b!qaqcFqi!I>7JcQUlbI*J{oWklG=2+SJX&iVK@zte3m_PGk} z#T9NlPUh^TbXZQD0pfHNRJgqa9c7TG5(lc@VnUoGM8O?ScLhN;F@RvXbfOP%X$%G{ zK9E2rdT~hwdYrVdF{Xzlj7LXC$M9AYWqCx3a2J;rt_V{wM5yOEVVNu2rPEk*RLHL?UBD0elcJ_pF z>TFTGD0ucpy~KipjX79<6(kg{f!MC7B7zA3w&Ou4TAusTuCXx!j8ts zV7Sp{JNYvaIHM=7rZ|{MrMHBpO?x?#SJ~OoC`hZ@l6)?e*i6!KzE6T@m9oL0h4`V$ z!tzRzyiI^Ot0!=$09~BSSC$4l{vJ~74UR<))S(>xfkrsD*M7UJ)Siz=D?BAPOtspj z32ge2mXwOaUkOi&$I@de(scHi%545vigZh?^w_mHje6%g_!&b_tw^5G^D0tRtn|0* z!0{=bor+NxU6_MI&j|d7{QP87DkD+H`ZhAfD@z@@nd-S*l|MCvUruXcbF=NJz znWeA99PRL|VdgCS<|Oths54Btt3#vV*_gk?`Z^?&qNaAlXa13!>L;%hu1UxKhg7qH|*dqa6m!wa?&_FTfk2Uc(H(w2>2-hXQgxgj|9A2z^wxQ zUcg;(kiz7T=lp2`zFEM90>-m@?DvR(KNs-F0-iI0)8l$^c`pd~IsspCEvGLO@L&P2 z5b(PKUMJwsGdTa30#?KmpJxQj4gtY(Wg^e7Lni0X67X07ml13XpUcz{+(DAm^PR^C z#u%WU*StwE`WT({)2~^;bmmXL9RjAafBNkw7&bL;28Yi8z8r17RKO;@=hqE7QvJ!P z0#^OTHwsuiulgS8wGrifR_vSH36>>@D2g56tDrhBKb`MP80CF zTX}sK3b;hTj|;d`!0!vVO2A(UxJJOg2zaT0lP=@=H3~RWz{>?ZPrxe#yhOk&1^l#t zn*`h<;MD@AGjS8fi!pdUg?==Q6HK46pkE#?g6TOH`rVC-V0xZ~esAM4K}YI2%qId? z&tDD_j6Bu9oAfhaBu9_pzb*jqA3cu$dg$PhIyhSg-=u>pbg*9sui!B5{P!0feY*}m zpo4$qFdfaZUmwJP3YC8}he@sMm#Kqi>fi-Bm>!>pJUT{azu)WVFX-S^I=Dp#AL20X z{C8Fd_drg_FI3)3b?`tPe6(aldgWu4l->if8GB~W? zQ#yKgSfaMRBXw|w4$jlT1v$v`e>n&U~*8dsTJGkD(wF=j2Tx)Rs71sy2KE&0GYdx+F zxHjVY2-jv@Ex5Me+KTIATr^kw4HtfycjD&9wG7w&xE{duAg*U{y@KlvTyNrP!lf?@ zmE$kC*5Y~(*Za8E;o5}jf1AEgCCPpvF96%=UyzG=1un>?d#~lfnd{zrks^KOS~mfw zoXd%Tzl;kH2cBP-&fyjoj{8XY%$Xm0bw*F){(3!@x#;ys?v-yB%betTitxR+L9_RC zbV|^?>d=PLu5jU1=fbrL!#e`(d4C}$lBA~6`pw%raXH5!i`^dSTW|kBC*mN6x!NNz z{Ai}_u?#SDETj4k+jGRXbEX%85@&eAQEzvs9(v)LSAFtfr@L@PhY|3uaxZ)YO8dcKyu5rjShr1A=LC+4ocTuQ5YfnB&;bIT-^9S%lJQ`QK;L-Zn1uD|H9zwS9s_Wh9 z+>ajNK<9w)oJYFMLy+*5U+6$bb)v&v&b;U6cAKB;IQ85|sps;rtN3=`Q{Y6jNfvwU zBLs#W?jcmj(;mV^y4X3oJ>NQ~Xr1aDqaL?LK*F~kffG)3j*C2$RdM{diq%5%E{S?n zt8%e}S}mY?6DPv!&Uv)%cEUvX*)@nZZ>6ZGz~o_9`Babl`CRQ6@Ucgb#cL^T-R(LT zyzsMY9qg)SokDV{Q^ClG7cuncG@I=yJ~+$9cTvtQccb z!otOCd&1`1zCD{aPH^OzN3#<_9Q&ZNRJggQR82V}-~6MKMLv_;+rD+1XC4#Dt(Tr> zHnZG#9~Q+Pt1Wi;-84~l{zj_i4co+6PYyM84*lXAb8YPICTS^T*IjwdgNt zx{iT&Zgu7;I)kP;c{5Xy)TN2K)QGHF-jqUN_9>BFiN1n3ObiCStDyQT}W0*Z;RJyyMB?Vu6SO;|xj zx0S3rt!^ie(Hg^N#nI%Uc`vn{lw&jlfT)Nry9=a`Y)4gZmhdae+G)O>0<=-QW(|-R z$saO+6rG8B=)KR`=620Aaw*4iUX^5?hd0QoiEfL*Z`|>WPpi=Mo zCuB611?p5zwSthgpJ%v8QJO9!MCr%o z3kp*86KM{tSg`eWztC`gnYzi7wWL=0qOWTnx6CtZ%o|-Pm9elV&|u8P72Fu~qf?vb zPjzAn`9Q22)zsxW|I`PK`ku(@@bYRD%L=1zn=p-V290T|455vb$~0Qj!&Ih-jg-pR zW+c*Vpw7vIBB}ed5RazVp*=Kh9wJo3E1>DD+NXUOcbY1gYhGX1_MhNIA@X>?HIKt5 z0bKOFP=S*>3ZP?c6Pr`#H;Tw@juU;#wx^S15qupVopgRZ85IdW{lJG@%$ldO&-K3BLNMa+LhA5#&_{1kj^hkee0 zp2mx;Arq65TwGd}&wO)O3DZNW*$%Ix9Y*swJmf{sd+`SVUF>5C)Np1|=P)Lc(_3BX zl&;UpvOB8^ot0jEegdE1Ft@>sZi5+v0*Z|lJ{H72%7f=qy?9d0Zg*9<>}>18EZvEZ zEzmy6%%1rQ`~GH3!vpl1eHgFtIL(8}?Q)DxVH|_RGx(4vPs`4a6vQ~Jvn?}_gJ$bI zQu~n=?xj30Q%XDj$~FZaqbYFP`j}Hx8?v$QlRyzEqp|x6FNJ82$Qy|i06qPeo6sD- z59C_De)j*RfQwt}x5@KjHV6@kP|dbqKZ*GG3E50aI=&AzzZB2q!;9W_Da9;iO!7H- zbZaGUhN;tm)b6EJ&w%{C9fKCCzyJ!v#n^LmrMe&W{Z^ zBE^GZlHoo&Ua_L;x{IJ%$RYb zlhcY)$C*>dq^6E8C>)cXUT7XuTsSs;bn@7Ov{a`w-gkVLv3^*u2YP+|+vnbKKh^xq z7LO`Q8-7|l^5?&0j+=OI_26UgWI7TC?%F%2!`~hq)i`bE&4JH~|7Gy+y6UCbA3ZpI z&yA-VyZ3(em49|@c{u%m`ObI0T(f%6QQ5aSE#>Ee+SnT^C!{@p>)@e-K41J^pP%wS z^Zu=A!1^U0j#_os@0R`hwc@g?@B8h@Z9YrO%i~Tj{$}%V*NKnbo3r-vnY*Wt9%4BD zR_C}Kn-fY4Z{F1V`Wc@rX}WXZYjrJN5p&zbkWZF{>!%hXNc?Zdrx%!t~3+sBt0^93Dxe^sFqI7BUGCd^FLPY^6I3f53a6V-17BjODdXvm$1IeRcm*A_V$L|8#+qa{iY=^Iz8{!Nk0th zoR)ptO}{29DU-6zpFMTuUek@wANr5EHetU~w91gMe$RDp#l7_YyTv2kK7H*kY13nvv-$Q98)%V zw*BSM(<6UL2zKq!Yry92YyQyt4&#GA4_z?r^d5TdjD4u2J@rO$Q4K^j5Y<3b15ph` zH4xQ6R0B~BL^TlAKvV-!4Ma5%)j(7OQ4K^j5Y<3b15ph`H4xQ6R0B~BL^TlAKvV-! z4Ma5%)j(7OQ4K^j5Y<3b15ph`H4xQ6R0B~BL^TlAKvV-!4Ma5%)j(7OQ4K^j5Y<3b v15ph`H4xQ6R0B~BL^TlAKvV-!4Ma5%)j(7OQ4K^j5Y<3b15pj=H1K}_*AGgV