From 217c9a30fcb8abcefbf06b62c8afd9fceaf867bc Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 14 Nov 2018 15:50:25 +0200 Subject: [PATCH] 2009-12-12 --- src/Canv.java | 399 +++++++++++++++++++++++++++++++++++++++++++++++ src/Effects.java | 54 +++++++ src/Engine2.java | 234 +++++++++++++++++++++++++++ src/SEPS.java | 32 ++++ src/icon.png | Bin 0 -> 857 bytes 5 files changed, 719 insertions(+) create mode 100644 src/Canv.java create mode 100644 src/Effects.java create mode 100644 src/Engine2.java create mode 100644 src/SEPS.java create mode 100644 src/icon.png diff --git a/src/Canv.java b/src/Canv.java new file mode 100644 index 0000000..1507ee9 --- /dev/null +++ b/src/Canv.java @@ -0,0 +1,399 @@ + +import com.sonyericsson.multimedia.*; +import com.sonyericsson.multimedia.control.*; +import java.io.IOException; +import java.util.Calendar; +import javax.microedition.io.Connector; +import javax.microedition.lcdui.*; +import javax.microedition.sensor.*; + +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +/** + * + * @author aNNiMON + */ +public class Canv extends Canvas implements Runnable, MediaControlListener { + + private int w,h; + private boolean lite, shift, axcel, vis; + private int mode; + private int accelPrevDelta = 0; + + private Image I, album; + private Engine2 e2; + private Graphics G; + private Thread thr; + private final Font medFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); + private final Font smallFont_b = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL); + + private MultimediaService service = null; + private MediaControl mediaControl = null; + private Media media = null; + + private int[] channels = new int[3]; + private String[] channelNames = new String[3]; + private SensorConnection sensor; + private String URL; + + public Canv() { + setFullScreenMode(true); + thr = new Thread(this); + thr.start(); + shift = lite = false; + vis = axcel = true; + mode = 0; //Режим плейера + w = getWidth(); + h = getHeight(); + I = Image.createImage(w, h); + G = I.getGraphics(); + getInfo(); + service = MultimediaServiceManager.getMultimediaService("MediaPlayer"); + mediaControl = (MediaControl)service.getControl("MediaControl"); + mediaControl.addMediaControlListener(this); + playTrack(); + } + + protected void paint(Graphics g) { + if(mode==0) drawPlayerCanvas(G); + g.drawImage(I, 0, 0, 20); + } + + private void drawPlayerCanvas(Graphics g) { + g.setColor(0); + g.fillRect(0, 0, w, h); + drawTitle(g, "SEPS by aNNiMON"); + int fh = smallFont_b.getHeight()+2; + int py = fh+fh/2; + g.setFont(medFont); + g.setColor(0x227A6F); + if (media != null) { + MetaData metaData = media.getMetaData(); + if (metaData != null) { + Object data = metaData.getValue(MetaData.TITLE_KEY); + if (data != null) py = drawText(g, "Заголовок: ", (String) data, py); + + data = metaData.getValue(MetaData.ALBUM_KEY); + if (data != null) py = drawText(g, "Альбом: ", (String) data, py); + + data = metaData.getValue(MetaData.ARTIST_KEY); + if (data != null) py = drawText(g, "Исполнитель: ", (String) data, py); + + data = metaData.getValue("filename"); + if (data != null) py = drawText(g, "Файл: ", (String) data, py); + + if (album != null) { + int ih = h-fh-2-py-20; + if(album.getHeight()>ih) album = Effects.Resize(album, ih*album.getWidth()/album.getHeight(), ih); + g.drawImage(album, w/2, py+15, 17); + }else if(vis){ + if(e2==null) { + int ih = h-fh-2-py-20; + e2 = new Engine2(ih, ih); + e2.setRun(true); + } + g.drawImage(e2.MainCanvas(), w/2, py+15, 17); + } + + if(axcel) { + g.setColor(0x992235); + g.drawString("Accel", 2, py+15, 20); + } + if(vis) { + g.setColor(0x992235); + g.drawString("Visual", 2, py+15+(smallFont_b.getHeight()+2), 20); + } + + float div = ((float)w - 10) / (float)media.getDuration(); + g.setColor(0x0000E6); + g.fillRect(5, py, (int)(media.getMediaTime() * div), 10); + g.setColor(0x009900); + g.drawRect(5, py, w-10, 10); + } + } + drawSoft(g, "Свернуть", "Выход"); + } + + public void keyPressed(int key) { + int ga=getGameAction(key); + if(key==-7) { + pauseTrack(); + SEPS.midlet.destroyApp(true); + } + if(key==-6) SEPS.midlet.dsp.setCurrent(null); + if(key==KEY_POUND) axcel=!axcel; + if(key==KEY_STAR) vis=!vis; + switch(ga) { + case LEFT: + prevTrack(); + break; + case RIGHT: + nextTrack(); + break; + case UP: + break; + case DOWN: + break; + case FIRE: + try { + if (mediaControl.getState() == mediaControl.STATE_PLAY) pauseTrack(); + else playTrack(); + } catch (Exception e) { + } + break; + } + repaint(); + } + + public void keyRepeated(int key) { + keyPressed(key); + } + + public int getDelta(int channel, int threshold) { + int delta = 0; + try { + Data[] data = sensor.getData(1, -1, false, false, false); + int drx = 0; + + for (int i = 0; i < data.length; i++) { + if (data[i].getChannelInfo().getName().equals(channelNames[channel])) { + drx = data[i].getIntValues()[0]; + } + } + + delta = channels[channel] - drx; + channels[channel] = drx; + + if (Math.abs(delta) < threshold) { + delta = 0; + } + } catch (Throwable t) { + } + + return delta; + } + + public void run() { + while (true) { + try { + final int delta = getDelta(0, 800); + + if (delta != 0) { + if (accelPrevDelta != 0 && (delta * accelPrevDelta) < 0) { + accelPrevDelta = 0; + } else { + accelPrevDelta = delta; + + Runnable runnable = new Runnable() { + + public void run() { + if (delta > 0 && axcel) { + nextTrack(); + } else if (delta < 0 && axcel) { + prevTrack(); + } + } + }; + (new Thread(runnable)).start(); + } + } + if(!vis) Thread.sleep(100); + if (service != null) { + repaint(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private void getInfo() { + SensorInfo[] info = SensorManager.findSensors("acceleration", null); + for (int i = 0; i < info.length; i++) { + SensorInfo s = info[i]; + URL = s.getUrl(); + ChannelInfo[] ci = s.getChannelInfos(); + for (int r = 0; r < ci.length; r++) { + ChannelInfo c = ci[r]; + channelNames[r] = c.getName(); + } + } + try { + sensor = (SensorConnection) Connector.open(URL); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + private void nextTrack() { + try { + mediaControl.next(); + } catch (ControlException ex) { + ex.printStackTrace(); + } + } + + private void prevTrack() { + try { + mediaControl.prev(); + } catch (ControlException ex) { + ex.printStackTrace(); + } + } + + private void pauseTrack() { + try { + mediaControl.pause(); + } catch (ControlException ex) { + ex.printStackTrace(); + } + } + + private void playTrack() { + try { + mediaControl.play(); + } catch (ControlException ex) { + ex.printStackTrace(); + } + } + + public static String getTime(int mode) { + String dd, mm, yy, _h, m, s; + Calendar cal = Calendar.getInstance (); + dd = String.valueOf (cal.get (Calendar.DAY_OF_MONTH)); + if (dd.length () == 1) + dd = "0" + dd; + mm = String.valueOf (cal.get (Calendar.MONTH) + 1); + if (mm.length () == 1) + mm = "0" + mm; + yy = String.valueOf (cal.get (Calendar.YEAR)); + _h = String.valueOf (cal.get (Calendar.HOUR_OF_DAY)); + if (_h.length () == 1) + _h = "0" + _h; + m = String.valueOf (cal.get (Calendar.MINUTE)); + if (m.length () == 1) + m = "0" + m; + s = String.valueOf (cal.get (Calendar.SECOND)); + if (s.length () == 1) + s = "0" + s; + String time; + if(mode==1) time = _h+":"+m+":"+s; + else if(mode==2) time = (dd+"."+mm+"."+yy.substring(2)); + else time = (dd+"."+mm+"."+yy.substring(2)+" "+_h+":"+m+":"+s); + return time; + } + + public void mediaControlUpdate(int eventId, ControlEvent event) { + try { + switch (eventId) { + case MediaControlListener.PLAY: + case MediaControlListener.PAUSE: + case MediaControlListener.STOP: + case MediaControlListener.ENDPLAY: + case MediaControlListener.FASTFORWARD: + case MediaControlListener.REWIND: + this.media = (Media) event.getData(); + break; + case MediaControlListener.ERROR: + //errorString = (String) event.getData(); + //canvas.removeCommand(pauseCommand); + //canvas.addCommand(playCommand); + break; + default: + break; + } + MetaData data = this.media.getMetaData(); + if (data != null) { + byte[] alb = data.getAlbumArt(); + if (alb != null) { + album = Image.createImage(alb, 0, alb.length); + } else { + album = null; + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + + } + + private void drawTitle(Graphics g, String text) { + int fh = medFont.getHeight()+4; + g.setColor(0x0000E6); + g.setFont(medFont); + g.drawString(text, w/2, 2, 17); + drawRect(g, 0xFF242424, 0x87282828, 0, 0, w, fh/2); + drawRect(g, 0x87151515, 0xFF181818, 0, fh/2, w, fh/2); + } + + public void drawRect(Graphics g, int color1, int color2, int x1, int y1, int w, int h) { + int a1 = (color1 >> 24) & 0xff; + int r1 = ((color1 & 0xFF0000) >> 16); + int g1 = ((color1 & 0x00FF00) >> 8); + int b1 = (color1 & 0x0000FF); + int a2 = (color2 >> 24) & 0xff; + int r2 = ((color2 & 0xFF0000) >> 16); + int g2 = ((color2 & 0x00FF00) >> 8); + int b2 = (color2 & 0x0000FF); + + int count = h / 3; + if (count < 0) { + count = -count; + } + if (count < 8) { + count = 8; + } + int crd1, crd2; + + for (int i = count - 1; i >= 0; i--) { + crd1 = i * h / count + y1; + crd2 = (i + 1) * h / count + y1; + if (crd1 == crd2) { + continue; + } + if(lite) { + g.setColor(i * (r2 - r1) / (count - 1) + r1, i * (g2 - g1) / (count - 1) + g1, i * (b2 - b1) / (count - 1) + b1); + g.fillRect(x1, crd1, w, crd2 - crd1); + }else{ + int[] pixelArray = new int[w * (crd2 - crd1)]; + for(int zi = 0; zi < pixelArray.length; zi++) + pixelArray[zi] = (int) ((i * (a2 - a1) / (count - 1) + a1) << 24) | + ((i * (r2 - r1) / (count - 1) + r1) << 16) | + ((i * (g2 - g1) / (count - 1) + g1) << 8) | (i * (b2 - b1) / (count - 1) + b1); + g.drawRGB(pixelArray, 0, w, x1, crd1, w, crd2 - crd1, true); + } + } + } + + private void drawSoft(Graphics g, String lsoft, String rsoft) { + int fh = medFont.getHeight()+2; + g.setColor(0x009900); + g.setFont(medFont); + g.drawString(lsoft, 2, h-2, 36); + g.drawString(rsoft, w-2, h-2, 40); + drawRect(g, 0xFF242424, 0x87282828, 0, h-fh, w, fh/2); + drawRect(g, 0x87151515, 0xFF181818, 0, h-fh/2, w, fh/2); + } + + private int drawText(Graphics g, String name, String value, int y) { + g.setColor(0x00BB00); + g.drawLine(3, y-1, w-3, y-1); + + g.setColor(0x009900); + g.setFont(smallFont_b); + g.drawString(name, 5, y, 20); + + int tw = 15+smallFont_b.stringWidth(name); + g.setColor(0x0000E6); + if(smallFont_b.stringWidth(value)>tw) { + g.translate(tw-10, g.getTranslateY()); + g.drawString(value, 2, y, 20); + g.translate(-(tw-10), -g.getTranslateY()); + }else g.drawString(value, w-5, y, 24); + + return y+(smallFont_b.getHeight()+2); + } +} \ No newline at end of file diff --git a/src/Effects.java b/src/Effects.java new file mode 100644 index 0000000..046bd80 --- /dev/null +++ b/src/Effects.java @@ -0,0 +1,54 @@ +import javax.microedition.lcdui.*; + +/** + * + * @author aNNiMON + */ +public class Effects { + + public static Image createScaledImage(Image image, int screenWidth, int screenHeight) { + int sourceWidth = image.getWidth(); + int sourceHeight = image.getHeight(); + Image sImg = Image.createImage(screenWidth, screenHeight); + Graphics g = sImg.getGraphics(); + int[] lineRGB = new int[sourceWidth]; + int[] sourcePos = new int[screenWidth]; // cache for x positions + { + /* + * Pre-calculate x positions with modified bresenham algorithm + * http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html + */ + int y = 0; + int eps = -(sourceWidth >> 1); + for (int x = 0; x < sourceWidth; x++) { + eps += screenWidth; + if ((eps << 1) >= sourceWidth) { + if (++y == screenWidth) { + break; + } + sourcePos[y] = x; + eps -= sourceWidth; + } + } + } + for (int y = 0; y < screenHeight; y++) { + image.getRGB(lineRGB, 0, sourceWidth, 0, y * sourceHeight / screenHeight, sourceWidth, 1); + for (int x = 1; x < screenWidth; x++) // skip pixel 0 + { + lineRGB[x] = lineRGB[sourcePos[x]]; + } + g.drawRGB(lineRGB, 0, screenWidth, 0, y, screenWidth, 1, false); + } + return sImg; + } + + public static Image Resize(Image temp, int newX, int newY) { + Image temp2; + try { + temp2 = createScaledImage(temp, newX, newY); + } catch (Exception e) { + return temp; + } + return temp2; + } +} diff --git a/src/Engine2.java b/src/Engine2.java new file mode 100644 index 0000000..24f0668 --- /dev/null +++ b/src/Engine2.java @@ -0,0 +1,234 @@ + +//import com.nokia.mid.ui.DeviceControl; +import javax.microedition.lcdui.*; +import java.util.Random; + +public class Engine2 implements Runnable { + + private Graphics G; + private Image db; + private int S = 15;//ветви + private int N = 20;//гибкость + private int K = 60; + private float L = (float) 1/1; + private int T = 0; //0-4 //line,time,rect + private int U = 9; + private int w,h; + + private boolean rb, gb, bb; + private float x, y, tx, ty, k, d, len; + private int rc = 0, gc = 0, bc = 0, rgb = 1, fr = 1, ar = 1; + private float[] a = new float[40]; + private Random rnd; + private Thread thr; + public boolean run; + + public Engine2(int w, int h) { + this.w=w; + this.h=h; + db = Image.createImage(w, h); + G = db.getGraphics(); + rnd = new Random(); + thr = new Thread(this); + thr.start(); + } + + public void run() { + while (run) { + int r = (rnd.nextInt() >>> 1) % 26; + switch(r) { + case 3: ar=(rnd.nextInt() >>> 1) % 14; break;//color + case 4: if(K<84) K+=15; break; + case 5: fr=((rnd.nextInt()>>>1)%6)+1; break;//formula + case 6: T = (rnd.nextInt() >>> 1) % 3; break;//фигуры + case 7: S += 4; break; + case 8: N += 5; if(N>=40) N=40; break; + case 9: N -= 5; if(N<5) N=5; break; + case 10: L = (float) 1/((rnd.nextInt() >>> 1)%8); break; + case 11: U=(rnd.nextInt() >>> 1) % 9; break; + case 14: if(K>16) K-=15; break; + } + + try { + Thread.sleep(2000L); + } catch (InterruptedException ex) {} + } + } + + public void setRun(boolean run) { + this.run=run; + } + + public Image MainCanvas() { + rgb(G); + visual(G); + return db; + + } + + private void rgb(Graphics grf) { + switch(rgb) { + case 1: + rc++; + if (rc > 253) rb = true; + if(rb) rc-=2; + if(rc<14 && rb) {rc=0; rb=false; rgb++;} + break; + case 2: + gc++; + if (gc > 253) gb = true; + if(gb) gc-=2; + if(gc<14 && gb) {gc=0; gb=false; rgb++;} + break; + case 3: + bc++; + if (bc > 253) bb = true; + if(bb) bc-=2; + if(bc<14 && bb) {bc=0; bb=false; rgb++;} + break; + case 4: + rc++; gc++; + if (rc > 253) rb = true; + if(rb) {rc=gc-=2;} + if(rc<14 && rb) {rc=gc=0; rb=false; rgb++;} + break; + case 5: + rc++; bc++; + if (rc > 253) rb = true; + if(rb) {rc=bc-=2;} + if(rc<14 && rb) {rc=bc=0; rb=false; rgb++;} + break; + case 6: + gc++; bc++; + if (gc > 253) gb = true; + if(gb) {gc=bc-=2;} + if(gc<14 && gb) {gc=bc=0; gb=false; rgb++;} + break; + case 7: + rc=gc=bc++; + if (gc > 253) gb = true; + if(gb) {rc=gc=bc-=2;} + if(gc<14 && gb) {rc=gc=bc=0; gb=false; rgb=1;} + break; + } + } + + private void visual(Graphics grf) { + if (w > h) { + len = (float) (h / L / N); + } else { + len = (float) (w / L / N); + } + k = (float) (Math.abs(rnd.nextFloat() * 360) * Math.PI / 180); + float r50 = (float) (Math.abs(rnd.nextFloat()) * 50); + d = (float) (Math.PI * 2 / S); + if (r50 < 2) { + k = (float) (Math.abs(rnd.nextFloat() * 1440) * Math.PI / 180); + } + a[0] = (float) (a[0] + Math.sin(k)/U); + for (int i = 1; i < N; i++) { + a[i] = (float) (a[i] + (a[i - 1] - a[i]) * 0.1); + + } + for (int j = 0; j < S; j++) { + x = (float) (0.5 * w); + y = (float) (0.5 * h); + for (int i = 1; i < N; i++) { + grf.setColor(rc, gc, bc); + if (fr == 1) { + tx = (float) (x + Math.cos(j * d + a[1]) * len); + ty = (float) (y + Math.sin(j * d + a[i]) * len); + x = x + (float) (Math.cos(j * d + a[i]) * len); + } + if (fr == 2) { + tx = (float) (x + Math.sin(j * d + a[i]) * len); + ty = (float) (y + Math.cos(j * d + a[i]) * len); + } + if (fr == 3) { + tx = (float) (x + Math.tan(j * d + a[1]) * len); + ty = (float) (y + Math.cos(j * d + a[i]) * len); + y = y - (float) (Math.sin(j * d + a[i]) * len); + } + if (fr == 4) { + tx = (float) (x + Math.tan(j * d + a[1]) * len); + ty = (float) (y + Math.cos(j * d + a[i]) * len); + x = y - (float) (Math.sin(j * d + a[i]) * len); + } + if (fr == 5) { + tx = (float) (x + Math.tan(j * d + a[1]) * len); + ty = (float) (y + Math.cos(j * d + a[i]) * len); + x = (float) (x * ty * d + a[i] - (float) (Math.sin(j * d + a[i]) * len)); + } + if (fr == 6) { + tx = (float) (x + Math.cos(j * d + a[1]) * len); + ty = (float) (y + Math.sin(j * d + a[1]) * len); + x = x + (float) (Math.sin(j * d + a[i]) * len); + y = y + (float) (Math.cos(j * d + a[i]) * len); + tx = (float) (x + Math.cos(j * d + a[1]) * len); + ty = (float) (y + Math.sin(j * d + a[1]) * len); + x = x + (float) (Math.sin(j * d + a[i]) * len); + y = y + (float) (Math.cos(j * d + a[i]) * len); + } + if (ar == 2) { + grf.setColor(255, (255 - 255 * i / N), 0); + } + if (ar == 3) { + grf.setColor(rc, (255 - 255 * i / N), 255); + } + if (ar == 4) { + grf.setColor((255 - 255 * i / N), 255, 0); + } + if (ar == 5) { + grf.setColor((255 - 255 * i / N), (255 - 255 * i / N), 255); + } + if (ar == 6) { + grf.setColor((255 - 255 * i / N), 255, 255); + } + if (ar == 7) { + grf.setColor(0, 255, (255 - 255 * i / N)); + } + if (ar == 8) { + grf.setColor(255, gc, (255 - 255 * i / N)); + } + if (ar == 9) { + grf.setColor(255, (255 - 255 * i / N), (255 - 255 * i / N)); + } + if (ar == 10) { + grf.setColor(rc, (255 - 255 * i / N), 0); + } + if (ar == 11) { + grf.setColor(255, (255 - 255 * i / N), 255); + } + if (ar == 12) { + grf.setColor((255 - 255 * i / N), 0, 255); + } + if (ar == 13) { + grf.setColor((255 - 255 * i / N), 255 * i / N, 0); + } + if (ar == 14) { + grf.setColor(bc, 255, (255 - 255 * i / N)); + } + if (T==0) grf.drawLine((int) x, (int) y, (int) tx, (int) ty); + if (T==1) grf.fillArc((int) tx, (int) ty, (int) x, (int) y, 0, 360); + if (T==2) grf.fillRect((int) tx, (int) ty, (int) x, (int) y); + x = tx; + y = ty; + } + } + if(K>=3) ACLS(grf); + else CLS(grf); + } + + private void CLS(Graphics g) { + g.setColor(0x00); + g.fillRect(0, 0, w, h); + } + + private void ACLS(Graphics g) { + int[] pixelArray = new int[w * h]; + for (int io = 0; io < pixelArray.length; io++) { + pixelArray[io] = (int) (100-K << 24) | (0 << 16) | (0 << 8) | 0; + } + g.drawRGB(pixelArray, 0, w, 0, 0, w, h, true); + } +} diff --git a/src/SEPS.java b/src/SEPS.java new file mode 100644 index 0000000..bb0eee5 --- /dev/null +++ b/src/SEPS.java @@ -0,0 +1,32 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +import javax.microedition.lcdui.Display; +import javax.microedition.midlet.*; + +/** + * @author aNNiMON + */ +public class SEPS extends MIDlet { + + public static SEPS midlet; + public Display dsp; + + public SEPS() { + midlet = this; + dsp = Display.getDisplay(this); + } + + public void startApp() { + dsp.setCurrent(new Canv()); + } + + public void pauseApp() { + } + + public void destroyApp(boolean unco) { + notifyDestroyed(); + } +} diff --git a/src/icon.png b/src/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e1f4ca241b3e7bc6ef99b874ed816874b85d6d GIT binary patch literal 857 zcmV-f1E&0mP)20009ZNkl0CmdPbV9k6o3jWMbzExZC8096Y;}VK!^VMaq8C-#0$hq@>VL4@U=MNiuevv4#!EP%Qx1sb~Z5=EwcAXB= z_Y_KV^(H7=Ag&|1uc*-XKOQT`4#e-K;I}ILwz&Ovpu}@ zuH%Hy+jhj7cBUux@MUi)0qdN@Gczx##-IkXgY=&uO^&u6QtBZ2M@X!Ngc>NXZenC) zM1lP^-Lby&8=0}(T2yvn&-mw^^_88N?_tdmc(WQ-9fpJ&OmyWxWbA9FwxP)j z$ZSr_9sTG2mZkJ#cuVVrrtY;8@%aP7P4`*+@!zOR?x8Ne%c5O(2-|*}ux+;}Jyh$3 z=GoIt3fhqrs-QU$U`+ndGa<3SLP(~Iko4=QQioA#ucAtpP$dnrAhDm_rekBaneWsp zsLr}Rl(qBTVRN)x*_2k#1WjH&3lh%BIV;EcB;B4I`1-hl7T9&Ug&mtH>fA`?srBw{ zr~2!Oei3q1AE8?)S9f8MyZWD26R)rFM6I=Xp~p`&D8OgEJJ`?`i>4`xxRX(CG(ucq zzG%l7@B(l6J{q@hIUiJep$>=pj}JJx+uk}poPU|_bS7EULjJ( zVuTxtle1d5$Fir?$?c&@U#U;Z4l@c{T7Um