2017年5月

Golang中的接口

软硬件环境

  • Windows 10
  • Go 1.8

什么是接口?

接口定义了一组方法,但是这些方法不包含实现的代码,另外接口里也不能包含变量。如下定义了一个接口

type intfNamer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
    ...
}

为什么要设计接口?

Go不是传统意义上的面向对象编程语言,它没有类及其继承的概念。接口是一种契约,实现类型必须满足它,它描述了类型的行为,规定类型可以做什么。接口彻底将类型能做什么,以及如何做分离开来,使得相同接口的变量在不同的时刻表现出不同的行为,这就是多态的本质。

简单接口示例

package main

import (
    "fmt"
)

type namer interface {
    area() int
}

type rect struct {
    width,height int
}

type square struct {
    side int
}

func (r rect) area() int {
    return r.height * r.width
}

func (s square) area() int {
    return s.side * s.side
}

func main() {
    var a = rect{4,3}
    var b  = square{6}

    fmt.Println(a.area())
    fmt.Println(b.area())
}

程序执行结果为

mtqq_mosquitto

测试某个值是否实现了某个接口?

type Stringer interface {
    String() string
}

if sv, ok := v.(Stringer); ok {
    fmt.Printf("v implements String(): %s\n", sv.String()) // note: sv, not v
}

接口嵌套

一个接口可以包含一个或者多个其它的接口,如下

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite
    Lock
    Close()
}

File接口包含了ReadWrite接口、Lock接口和方法Close,任何实现了File接口的类型同时也实现了接口ReadWrite和Lock

需要注意的点

  • 类型不需要显式地声明它实现了某个接口,接口被隐式地实现,多个类型可以实现同一个接口
  • 一个类型可以实现多个接口
  • 实现了某个接口的类型,可以有其它的方法

接口方法中类型T和T*的区别

type typeA struct {

}

type intfA interface {
    func1()
}

func (a *typeA) func1() {

}

func func2(i intfA)  {
    i.func1()
}

var a typeA

上面的例子中,在a上调用func2时,会导致一个编译器错误,因为func2需要一个intfA,而它的方法func1之定义在指针上。

Go 语言规范定义了接口方法集的调用规则:

  • 类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
  • 类型 T 的可调用方法集包含接受者为 T 的所有方法
  • 类型 T 的可调用方法集不包含接受者为 *T 的方法

小结

综上所述,接口就是一组方法的集合。 只要一个类型实现了某个接口中的方法,那么,这个接口类型的变量就可以接受这个类型的变量,而且同一个接口,可以接收不同类型的变量。

Android中的service简介

软硬件环境

  • ubuntu kylin 14.04
  • 红米note增强版
  • Android studio 0.8.6

概述

Service就是Android系统中的服务。Service不像Activity,它无法直接和用户进行交互,必须由用户或者程序显式地启动。另一方面,Service的优先级比较高,这就使得当系统资源紧缺时,Service被销毁的机率非常低。一般来说,类似在当前系统交互中想继续处理其它数据类似的场景就会使用到Service,如想一边看电子书一边听音乐。

Service的生命周期

相比Activity的生命周期,Service的会简单很多

void onCreate();
int onStartCommand(Intent intent,int flags,int startId);//替换了原来的onStart(Intent intent);
void onDestroy();

Service从onCreate开始,到onDestroy结束,onStartCommand启动Service。如果Service已经启动,而我们再次去启动时,不会执行onCreate方法,而是直接去执行onStartCommand方法。如图所示:

上图列出了2种启动Service的方式,一种是通过startService,另一种是通过bindService。

Activity和Service通信实例

目标效果图如下

新建工程AndroidServiceDemo,Activity名称为AndroidServiceDemoActivity,然后在源码目录创建一个service文件AndroidServiceDemo.java,即Android studio中的右键-->New-->Service-->Service。

布局文件activity_android_service_demo.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".AndroidServiceDemoActivity">

<Button
    android:id="@+id/startButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Start Service" />

<Button
    android:id="@+id/stopButton"
    android:layout_below="@+id/startButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Stop Service" />

<TextView
    android:id="@+id/textFake"
    android:layout_below="@+id/stopButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<Button
    android:id="@+id/bindButton"
    android:layout_below="@+id/textFake"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Bind Service" />

<Button
    android:id="@+id/unbindButton"
    android:layout_below="@+id/bindButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Unbind Service" />

</RelativeLayout>

AndroidManifest.xml文件由android studio自动生成,不需要改动,注意下service标签就可以了,每个service对应一组标签。

<service
    android:name=".AndroidServiceDemo"
    android:enabled="true"
    android:exported="true" >
</service>

接下来看看创建的service的代码AndroidServiceDemo.java

package com.macernow.djstava.androidservicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class AndroidServiceDemo extends Service {

    private static final String TAG = "AndroidServiceDemo";

    public AndroidServiceDemo() {
    }

    @Override
    public IBinder onBind(Intent intent){
        Log.e(TAG,"onBind... ...");

        return null;
    }

    @Override
    public void onCreate(){
        Log.e(TAG,"onCreate... ...");
        super.onCreate();
    }

    @Override
    public void onDestroy(){
        Log.e(TAG,"onDestroy... ...");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        Log.e(TAG,"onStartCommand... ...");
        return super.onStartCommand(intent,flags,startId);
    }
}

onBind方法需要返回一个IBinder对象,简单起见,这里直接返回null了。

最后看看Activity的相关代码AndroidServiceDemoActivity.java

package com.macernow.djstava.androidservicedemo;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class AndroidServiceDemoActivity extends Activity {
    private static final String TAG = "AndroidServiceDemoActivity";
    private static Button mStartButton,mStopButton,mBindButton,mUnbindButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_service_demo);

        mStartButton = (Button) findViewById(R.id.startButton);
        mStopButton = (Button) findViewById(R.id.stopButton);
        mBindButton = (Button) findViewById(R.id.bindButton);
        mUnbindButton = (Button) findViewById(R.id.unbindButton);

        mBindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mBindButton... ...");
                bindService(new Intent(AndroidServiceDemoActivity.this,AndroidServiceDemo.class), mConnection, BIND_AUTO_CREATE);
            }
        });

        mStartButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mStartButton... ...");
                startService(new Intent(AndroidServiceDemoActivity.this,AndroidServiceDemo.class));
            }
        });

        mStopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mStopButton... ...");
                stopService(new Intent(AndroidServiceDemoActivity.this,AndroidServiceDemo.class));
            }
        });

        mUnbindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mUnbindButton... ...");
                unbindService(mConnection);
            }
        });
    }

    ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG,"onServiceConnected... ...");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG,"onServiceDisconnected... ...");
        }
    };

    @Override
    protected void onDestroy(){
        Log.e(TAG,"onDestroy... ...");
        unbindService(mConnection);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.android_service_demo, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

上面代码中出现了一个ServiceConnection类,并实现了onServiceConnected和onServiceDisconnected方法。一般来讲,bind service后的处理操作放在onServiceConnected方法中进行。而bindService和unbindService方法都是对ServiceConnection对象进行操作。

依次点击应用界面上的4个按钮,logcat中的打印如下

可以看到stopService和unbindService都是调用的onDestroy方法。

参考资料

1、http://developer.android.com/reference/android/app/Service.html
2、http://developer.android.com/guide/topics/manifest/service-element.html

Lighttpd交叉编译及使用

软硬件环境

  • ubuntu kylin
  • lighttpd-1.4.35
  • mips toolchain
  • broadcom 7581

概述

Web服务器的主要功能是提供网上信息浏览服务。目前主流的Web Server有apache、nginx和kangle等,不过上述这些都体能齐全、体积庞大,如果想要在嵌入式设备上使用它们,显然是不现实的。本文介绍一种轻量级的web server,它能够很好地满足你的要求并且表现出色,它就是lighttpd。

交叉编译

  1. 下载源码,本文使用的是1.4.35版本
    http://www.lighttpd.net/download/

  2. 编译(安装目录可以自行修改/home/djstava/Downloads/lighttpd-1.4.35/install)

    tar xvf lighttpd-1.4.35.tar.gz

    cd lighttpd-1.4.35    
    
    ./configure --prefix=/home/djstava/Downloads/lighttpd-1.4.35/install --host=mipsel-linux-gnu --disable-lfs --disable-ipv6 --without-openssl --without-kerberos5 --without-pcre --without-zlib --without-bzip2 --without-lua "CC=mipsel-linux-gcc -EL" "CFLAGS=-EL" "LDFLAGS=-EL"        
    make        
    make install        
    
  3. 配置

    cd /home/djstava/Downloads/lighttpd-1.4.35/install

    mkdir -p cache cgi-bin config log sockets vhosts webpages        
    
    cp -rf lighttpd-1.4.35/doc/config/config.d lighttpd-1.4.35/doc/config/lighttpd.conf lighttpd-1.4.35/doc/config/modules.conf config/        
    修改config/lighttpd.conf
    
    var.log_root    = "/home/djstava/Downloads/lighttpd-1.4.35/install/log"    
    var.server_root = "/home/djstava/Downloads/lighttpd-1.4.35/install"    
    var.state_dir   = "/home/djstava/Downloads/lighttpd-1.4.35/install"    
    var.home_dir    = "/home/djstava/Downloads/lighttpd-1.4.35/install"    
    var.conf_dir    = "/home/djstava/Downloads/lighttpd-1.4.35/install/config"    
    server.document-root = server_root + "/webpages"    
    server.username  = "lighttpd"
    #server.groupname = "lighttpd"  
    
  4. 测试页面,将下面代码保存到webpages/index.html

     <html>
    <head>
    <title>lighttpd test</title>
    </head>
    <body>
    <p>lighttpd for mips-linux</p>
    </body>
    </html>
    

在嵌入式设备上部署lighttpd(broadcom 7581)

  1. mkdir -p /home/djstava/Downloads/lighttpd-1.4.35/

  2. 将上面编译配置好的install文件夹copy到第一步中创建好的文件夹下

  3. 启动lighttpd

    cd /home/djstava/Downloads/lighttpd-1.4.35/install

     sbin/lighttpd -f config/lighttpd.conf
    
  4. 测试
    在pc浏览器中访问,如http://192.168.1.100/index.html,此处192.168.1.100是嵌入式设备的ip地址,请根据实际情况替换。

References

1、http://www.lighttpd.net/

gSOAP实现web service

Web Service

Web Service就是为应用程序提供的一个网络接口。客户端发送数据,服务端获取数据并进行处理,然后将结果返回给客户端,从而达到交互和分布式处理的效果,与平台、与开发语言无关。

WSDL文件

WSDL文件提供了一种对函数、函数参数及返回值描述的标准的xml文件.WSDL简化了开发流程,我们只要从服务提供商处获得相应接口的wsdl文件,通过该文件,利用软件自动生成客户端不同语言的代码。

搭建gSOAP环境

下载地址 http://sourceforge.net/projects/gsoap2/files/latest/download?source=file

unzip gsoap_2.8.9.zip
cd gsoap-2.8/src
make -f MakefileManual(生成soapcpp2)

cd gsoap-2.8/wsdl
make -f MakefileManual(生成wsdl2h)

示例程序

这里借用互联网上的一个例子。客户端输入两个数字,服务端提供加法函数服务并将结果返回给客户端。因为这个例子相对简单,就不用wsdl文件,而是直接从头文件开始生成代码。

创建工作目录

mkdir gSoapTest

拷贝所需文件

将gsoap源码包中的stdsoap2.c、stdsoap2.h及上面产生的soapcpp2拷贝到工作目录,如果有wsdl文件,则swdl2h也需要拷贝过来。

定义函数声明文件add.h,定义函数接口

int ns2_add(int num1,int num2,int *sum);

调用soapcpp2生成远程调用需要的文件

soapcpp2 -c add.h

创建服务端程序addserver.c

#include "soapH.h"
#include "add.nsmap"

int main(int argc, char **argv) 
{
    int m, s;
    struct soap add_soap;
    soap_init(&add_soap);
    soap_set_namespaces(&add_soap, namespaces);
    if (argc < 2) 
    {
        printf("usage: %s <server_port> \n", argv[0]);
        exit(1);
    } 
    else 
    {
        m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);
        if (m < 0) 
        {
            soap_print_fault(&add_soap, stderr);
            exit(-1);
        }
        fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
        for (;;) 
        {
            s = soap_accept(&add_soap);
            if (s < 0) 
            {
                soap_print_fault(&add_soap, stderr);
                exit(-1);
            }
            fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);
        soap_serve(&add_soap);
        soap_end(&add_soap);
        }
    }
    return 0;
}

int ns2__add(struct soap *add_soap, int num1, int num2, int *sum) 
{
    *sum = num1 + num2;
    return 0;
}

创建客户端程序addclient.c

#include "soapStub.h"
#include "add.nsmap"

int add(const char *server, int num1, int num2, int *sum) 
{
    struct soap add_soap;
    int result = 0;
    soap_init(&add_soap);
    soap_set_namespaces(&add_soap, namespaces);
    soap_call_ns2__add(&add_soap, server, NULL, num1, num2, sum);
    printf("server is %s, num1 is %d, num2 is %d\n", server, num1, num2);
    if (add_soap.error) 
    {
        printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap));
        result = add_soap.error;
    }
    soap_end(&add_soap);
    soap_done(&add_soap);
    return result;
}

创建测试程序addtest.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int add(const char *server, int num1, int num2, int *sum);

int main(int argc, char **argv) 
{
    int result = -1;
    char server[128] = {0};
    int num1;
    int num2;
    int sum;

    if (argc < 4) 
    {
        printf("usage: %s <ip:port> num1 num2 \n", argv[0]);
        exit(1);
    }

    strcpy(server,argv[1]);
    num1 = atoi(argv[2]);
    num2 = atoi(argv[3]);
    result = add(server, num1, num2, &sum);
   
    if (result != 0) 
    {
        printf("soap error, errcode=%d\n", result);
    } 
    else 
    {
        printf("%d + %d = %d\n", num1, num2, sum);
    }
    return 0;
}

编译程序

gcc -o addserver addserver.c soapH.h stdsoap2.h stdsoap2.c soapServer.c soapC.c
gcc -o addclient addclient.c soapH.h stdsoap2.h stdsoap2.c soapClient.c soapC.c addtest.c

运行程序

Server端:   ./addserver 7788
Client端:   ./addclient 127.0.0.1:7788 45 55

参考资料

1、http://liuskysun.blog.163.com/blog/static/9981297820101030421880/
2、http://www.cppblog.com/woaidongmao/archive/2008/05/28/51400.aspx
3、http://gsoap2.sourceforge.net/

phpstorm 2017.1.3版本破解

软硬件环境

  • windows 10
  • phpstorm 2017.1.3

离线激活

jetbrains已经屏蔽了很多的破解方法,所以最安全的还是离线激活。

修改hosts文件

找到 C:\Windows\System32\drivers\etc\hosts,增加配置语句

0.0.0.0 account.jetbrains.com

默认情况下,修改完该文件是无法保存的,这是出于安全因素的考虑。解决方法是打开hosts文件属性,增加写的属性。

获取激活码

这里要感谢lanyus,提供了几乎所有jetbrains的ide的破解方法。如果经济条件允许的话,还是建议去购买正版。最后贴一个可用的注册码

CNEKJPQZEX-eyJsaWNlbnNlSWQiOiJDTkVLSlBRWkVYIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiIiwiYXNzaWduZWVFbWFpbCI6IiIsImxpY2Vuc2VSZXN0cmljdGlvbiI6IkZvciBlZHVjYXRpb25hbCB1c2Ugb25seSIsImNoZWNrQ29uY3VycmVudFVzZSI6ZmFsc2UsInByb2R1Y3RzIjpbeyJjb2RlIjoiQUMiLCJwYWlkVXBUbyI6IjIwMTgtMDEtMzAifSx7ImNvZGUiOiJETSIsInBhaWRVcFRvIjoiMjAxOC0wMS0zMCJ9LHsiY29kZSI6IklJIiwicGFpZFVwVG8iOiIyMDE4LTAxLTMwIn0seyJjb2RlIjoiUlMwIiwicGFpZFVwVG8iOiIyMDE4LTAxLTMwIn0seyJjb2RlIjoiV1MiLCJwYWlkVXBUbyI6IjIwMTgtMDEtMzAifSx7ImNvZGUiOiJEUE4iLCJwYWlkVXBUbyI6IjIwMTgtMDEtMzAifSx7ImNvZGUiOiJSQyIsInBhaWRVcFRvIjoiMjAxOC0wMS0zMCJ9LHsiY29kZSI6IlBTIiwicGFpZFVwVG8iOiIyMDE4LTAxLTMwIn0seyJjb2RlIjoiREMiLCJwYWlkVXBUbyI6IjIwMTgtMDEtMzAifSx7ImNvZGUiOiJEQiIsInBhaWRVcFRvIjoiMjAxOC0wMS0zMCJ9LHsiY29kZSI6IlJNIiwicGFpZFVwVG8iOiIyMDE4LTAxLTMwIn0seyJjb2RlIjoiUEMiLCJwYWlkVXBUbyI6IjIwMTgtMDEtMzAifSx7ImNvZGUiOiJDTCIsInBhaWRVcFRvIjoiMjAxOC0wMS0zMCJ9XSwiaGFzaCI6IjUxOTU1OTMvMCIsImdyYWNlUGVyaW9kRGF5cyI6MCwiYXV0b1Byb2xvbmdhdGVkIjpmYWxzZSwiaXNBdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlfQ==-QOxwjWvRwJz6vo6J6adC3CJ4ukQHosbPYZ94URUVFna/Rbew8xK/M5gP3kAaPh6ZDveFdtMR1UBoumq3eCwXtXM3U3ls5noB4LIr+QplVlCj2pK5uNq7g/feyNyQcHpSXtvhIOnXDBLOecB05DOsxzm0p7ulGGJoAInmHeb9mc0eYjqc4RPpUQfh6HSYBnvEnKMlLF5bz4KEtzmsvvgA55CwzwQ3gRitm5Q/wUT7AQCBdjmBfNUjKVQL6TSjSDPp56FUdEs4Aab8LqstA2DIMbxocO64rvytmcUeIwu8Mi5uq87KQP5AQMSMYb59Inbd+dmVfx5cJo3fRS4/5s3/Hg==-MIIEPjCCAiagAwIBAgIBBTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE1MTEwMjA4MjE0OFoXDTE4MTEwMTA4MjE0OFowETEPMA0GA1UEAwwGcHJvZDN5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQC9WZuYgQedSuOc5TOUSrRigMw4/+wuC5EtZBfvdl4HT/8vzMW/oUlIP4YCvA0XKyBaCJ2iX+ZCDKoPfiYXiaSiH+HxAPV6J79vvouxKrWg2XV6ShFtPLP+0gPdGq3x9R3+kJbmAm8w+FOdlWqAfJrLvpzMGNeDU14YGXiZ9bVzmIQbwrBA+c/F4tlK/DV07dsNExihqFoibnqDiVNTGombaU2dDup2gwKdL81ua8EIcGNExHe82kjF4zwfadHk3bQVvbfdAwxcDy4xBjs3L4raPLU3yenSzr/OEur1+jfOxnQSmEcMXKXgrAQ9U55gwjcOFKrgOxEdek/Sk1VfOjvS+nuM4eyEruFMfaZHzoQiuw4IqgGc45ohFH0UUyjYcuFxxDSU9lMCv8qdHKm+wnPRb0l9l5vXsCBDuhAGYD6ss+Ga+aDY6f/qXZuUCEUOH3QUNbbCUlviSz6+GiRnt1kA9N2Qachl+2yBfaqUqr8h7Z2gsx5LcIf5kYNsqJ0GavXTVyWh7PYiKX4bs354ZQLUwwa/cG++2+wNWP+HtBhVxMRNTdVhSm38AknZlD+PTAsWGu9GyLmhti2EnVwGybSD2Dxmhxk3IPCkhKAK+pl0eWYGZWG3tJ9mZ7SowcXLWDFAk0lRJnKGFMTggrWjV8GYpw5bq23VmIqqDLgkNzuoog==