Try_to_writecode_practicaltest #atest_hack
-
Upload
kimukou26-kimukou -
Category
Technology
-
view
4.362 -
download
2
description
Transcript of Try_to_writecode_practicaltest #atest_hack
実務に近い
テストコードを
書いてみる
@kimukou2628
〜はじめに〜
・主旨的なもん
雑学的なネタな話なので、すごく気楽に聞いてください(中身が興味ないネタだったらすみません)
もしガチなテストの話を期待したテスト充な人がいましたら多分期待にそえません。スミマセン><寝ててもOKです~ (15分の分のみ解説補足する予定です)
・書いてみたきっかけ
テストの話は結構多いんですけど
「普通のプログラムコードみたいに
ググッてコピペみたいな話まで
書いてくれていないので(ググり駆動?)、
とっつきづらい」という話がよくでます
で実務に使うコードって何?=>お金に絡むコードじゃない?=>じゃあAd絡みのお話で書いてみましょう
〜前提知識のような物?〜
広告単語に関して基礎知識
<正式な語句は違うかもしれません(あしからず
● スポット広告○ 一定クリック数に達したら終了する広告
● 期間広告○ 一月とか期間中ずっと出しっ放しの広告
● 入稿○ 広告主が広告を出すこと
● 在庫○ 出す広告が存在していること
枠をおさえる 昔:特定のWebサイトの広告枠を確保 今:特定アプリの広告枠を確保に変わったイメージ
なんでMediation注目されているの?
● 理由1)○ AdWhirlが今年廃止になった
■ =>○ AdMobのMediationで管理してねの流れ
● 理由2)○ 最近ソーシャルバブルが弾け気味のせいか
スポット広告が増えた
● 規定クリック数を超えてクリック○ =>
● 支払い金額を減額等のペナルティ
○ 「配信サーバーの負荷上げないで〜」とAd広告会社さんより連絡が来る><
で何がおこったの?
●PV数とクリック数を自社で把握できる
=>
● 規定クリック数で非表示する等の設定も可能
らしい
●各社広告主の抱え込みをしている
○ AdlantisがGREE,MedibaがAUとか
○ 週代わり等のタイミングで値段が違ったりする
○ AdMobは一番安め〜><。適宜切替がベスト
で何でMediation?
〜実際のテストのお話〜
なんでテストが必要?(Mediationレイヤー)
● CustomEventBanner継承クラスが現在は必要
○ 日本の国内Ad広告に対してAdapterが提供されてないから
○ =>自前で作りましょう の流れ
● AdMob SDKのソースはAndroid版は非公開(IOS版はソースもろらしいですが。。
■ <そもそも2009年頃にAdMobはGoogleが買収した会社
■ ステップデバック等でも結構限界がある
● 実際試してみて呼び出し周期がどうも一定しないような感じ
■ 偏って呼ばれる感じがする。。
■ AdWhirlの頃はもっと安定していたらしいが。。。発展途上?
なんでテストが必要?(Ad側)
● Ad SDK自体がWebViewをくるんだカスタムレイアウト+αなので○ WebViewの不安定さに引きずられる
=>よく「アプリ落ちる」という話題はこれ
○ 作り自体もNWの調子が良いことが前提で作られている(通信エラー対応とかしてない。粗い)■ ココらへんはAdMobとかも同じ
=>● 広告会社さん的には
○ クリック率を上げるために■ 視聴者にあった広告を出すための情報収集■ 収集しやすい形にする為に鯖側も改修
● =>常に最新使ってね(更新がすごい早い)● 落ちるときはアプリ側で頑張って
Mediationの動き的な話
AdMob管理鯖
端末側(AdMob 6.1.0導入)
loadAd 枠キー送信 (またはメディエーションキー)
キーに対応したクラスを読込なさい&情報送信(サーバーパラメータ)
指定されたクラスファイルがサーバーパラメータ受信する形で呼ばれる
例) com.nihon0tc.ad.MedibaMasAdのような指定の仕方
CustomEventBannerを継承したクラス com.nihon0tc.ad.MedibaMasAd
@Overridepublic void requestBannerAd( final CustomEventBannerListener listener,
final Activity activity, String label, String serverParameter, AdSize adSize, MediationAdRequest request) {
listener.onReceivedAd(View)で他の広告SDKのViewをAddViewする
Exception等で失敗したら
listener.onFailedToReceiveAd();で「新しいリクエストおくれ」
と再リクエストを行う<手動
テストコンセプトとして
● requestBannerAdを直接叩く○ 単体のAd SDKが初期化エラー等がおきないような検証
○ onFailedToReceiveAdの段階では
テストを失敗させるようにCustomEventBannerListenerのMockを作ってAdMobの動きをエミュレートする
● 単一のCustomEventBannerをよぶようなメディエーションIDを設定して初期化する○ 全部を呼ぶようなメディエーションIDを設定できるがどう
も偏っていてテストしづらい
管理画面の設定イメージ
メディエーション設定数
● こんな感じに設定していても偏る
● こんな感じに設定していても偏る
配信比率
フルパッケージクラス名
サーバーパラメータ枠キーとかおくると良?
〜デモ〜
〜テストコード情報補足〜
テスト構成ライブラリプロジェクト AdManager
メインプロジェクト template_canvas
テストプロジェクト template_canvas_test
● 枠キー情報(ad_key.xml)は下記に有○ ライブラリプロジェクト(定義だけで中身は空)○ メインプロジェクト(実際のキーを記述)
<ライブラリプロジェクト側のキーはfinalで無いので上書き可能
● メインプロジェクトのAndroidManifest.xmlに○ AdMob○ Mediba
の広告用のActivityの記述を追記する(各Adの説明書に依存)
● テストプロジェクト側に○ テスト用のメディエーションキー配列(ad_key_test.xml)配置
実行時のイメージ
● duckをクリックする毎に上下に広告位置が変更されるイメージ
● 最近の流行で(ゲーム)画面をOpenGLで作る事が多いようなのでFrameLayoutで広告を重ねています
● レポジトリは
○ https://github.com/nihon-tc/mediationtest
参照してください
リソースの参照
● テスト書いてて混乱したので整理○ com.nihon0tc.example.test.R○ com.nihon0tc.example.R
と明示してIDを指定した方が混乱が無いようです(ここら辺は常識かも知られませんが<汗)
テスト対象のリソース参照 getActivity().getResource() またはgetInstrumentation().getTargetContext().getResources()
テストプロジェクトのリソース参照(テストデータとか)
getInstrumentation().getContext().getResources()
AdMobの初期化の仕方の修正
● 実装観点から■ 本来はメディエーションキー/枠キーは固定なので
■ レイアウトから呼ぶ形でも良いはず
LayoutInflater inflater = activity.getLayoutInflater();ViewGroup adParentView =(ViewGroup)inflater.inflate(R.layout.ad, null);adMob = (AdView)adParentView.findViewById(R.id.AdMob_medview);
<?xml version="1.0" encoding="utf-8"?><com.google.ads.AdView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
android:id="@+id/AdMob_medview" android:layout_width="320dip"
android:layout_height="70dp" ads:adUnitId="@string/adUnitId_mediation" ads:adSize="BANNER" ads:loadAdOnCreate="false" />
● テスト観点から■ 動的に生成しないとMediation_IDが再設定できない
● AdMobさんの方であとからキーを再設定できる関数がな
い
■ ココらへんは微妙かなと思う面もある
String key = activity.getResources().getString(R.string.adUnitId_mediation)adMob = new AdView(activity, AdSize.BANNER, key)
CustomEventBannerListenerのMock(挙動推測から下記イメージで
import com.google.ads.AdView;import com.google.ads.mediation.customevent.CustomEventBannerListener;
public class MockEventBannerListener implements CustomEventBannerListener{
@Overridepublic void onFailedToReceiveAd() {
throw new RuntimeException("onFailedToReceiveAd");}@Overridepublic void onReceivedAd(View arg0) {
ViewGroup parent = (ViewGroup)arg0.getParent();if(parent !=null) parent.removeAllViews();adMob.addView(arg0);
}}
〜テスト対象情報補足〜
メディエーション・Adの導入的な話は
● @HiroakiKamata さんの記事
○ テクノード鎌田社長に聞いた!ゼロから分かるAdMobメディエーションツール導入方法■ http://android.dtmm.co.jp/development/32475
● Ad広告自体の話
○ ad-stirさんの Android SDKの使い方■ http://wiki.ad-stir.com/Android_SDK%E3%81%
AE%E4%BD%BF%E3%81%84%E6%96%B9あたりを参考に
CustomEventBunner実装時の注意点(1)
● 一度作ったAdのインスタンスはstatic変数に確保した方が良○ Ad広告会社さん毎にアクティブ数管理してる
○ 何度もCustomEvent発行されるたびに作り直すのは非推奨
● 複数の画面レイアウトを切り替えている場合は、理想は
AdMobの枠自体を
○ 前の画面から外す(RemoveView)
○ 今の画面の指定位置に追加(AddView)
する形が良いかと思う(最近はredirect-urlを挟んで誤クリック判定等も厳しくなっているので、誤クリックしに
くいレイアウト配置も大事)
CustomEventBunner実装時の注意点(2)
● NW状態悪いと何回も通信リトライする物も
○ 重くなる原因■ Androidは通信がらみが重くなる■ GoogleAnalytics もANRでる原因になる事も
○ 可能であばNW状態が悪いときはローテトを止める■ Receiver等でConectivityManagerを監視する話はググると出てきます
が、3G環境は4系から動くようになっているので2系は厳しめ(READ_PHONE_STATE追加で電波状況判定等を入れると騒がれるから対応難な面も)
■ 表示Activeかみて動いている物もあるようなので、オフライン時に一時
的にレイアウトから外す手も(なら広告入れるな議論する人もいるけど霞食って生きてはいけない
はずなんだけどな・・orz)
CustomEventBunner実装時注意点(3)
● リアルタイム製を重視するゲームの場合はゲーム中は
pause等できるなら検討する
○ でもずっと止めてると単価はのびないかも・・
○ 対応が入っていない物も結構あるorz
■ (1個ローテート用のスレッドが動いているイメージ)
● onReceivedAd関数のタイミングでAddViewし直しているイ
メージなので
○ 切替前にはpauseかけられる物は止める
■ ローテート中に切り替えるとエラーになる事も
■ 可能であればアクティブな物のみ動かすようにする
○ 切替後に再始動(resume)のイメージ
CustomEventBunner実装時注意点(4)
● Ad自体に対して
● 基本Layoutだけでいきたかったりするが、日本でのAd自体が微
妙に使いづらいので、動的生成にならざるをえないのが難点(逆にレイアウト固定の物も)
○ infrate初期化後に広告枠のキーを設定して初期化等の関数が用意されて
なかったり
○ 動的コンストラクタのパラメータか、レイアウトのパラメータとして設定すると
かの形になったりする
● アクセスキャッシュをtmpにガンガン貯める物も多いのでアプリ側でちょ
びちょび消さないと内部メモリを圧迫する
○ 最近はユーザ領域にsqliteでデータキャッシュする物もあるようなのでこれ
の対処は困り者><(ユーザ領域のデータ消すのは。。
広告種別 Manifest記載 layout /code対応 resume/pouse(?)有無
AdMob △(Activity) ◎ ◎
AdLantis △(コード対応可) ◎ ×
Mediba △(Activity) ◎ ◎
AMoAd - ◎ ◎
iMobile △(PubKey) ◎(枠Key設定可) ◎
MicroAd ◎(Key) ◎ ×
Fluct △(コード対応可) ◎ ×
AdPapri - layoutのみ ◎
Nend - ◎ ◎
AdStir △(コード対応可) ◎ ×
resume/pause 対応の広告は増えてほしいかな・・とは正直思いますね・・
resume/pouse関数等の(?)有無確認自体は
● ドキュメントに書いていない場合は● JD-GUI辺りを使いましょう
○ http://java.decompiler.free.fr/?q=jdgui○ コード自体はurl特定によるDOSアタック対策(負荷対策)
のせいかProGuardかかっている物も多いです
■ 本来 ● 枠キー & 端末の環境情報をPOST● その情報に適した広告ページを端末に配信(GET)してるイメージなので。(理想は性別と年齢が欲しいでしょうね<AdMobの設定例にあるし。女性や年配の方のほうがやはりお金持ってるかも)
〜テスト的な課題(出来てない事)〜
● 長時間ランニングテスト○ 担当者レベルの単体テストで終わってる
○ 収益性的には重要だが魅力あるコンテンツ作成に開発者としては力を割きたい■ =>
○ でもユーザさんからは
■ 「長時間動かしていると、アプリがどんどん重くなる」というPlayコメ等は頂いている状態
● 特定のAd SDKで起きる現象○ 特定の条件下でViewの初期化失敗
■ =>
○ onFailedToReceiveAdのリトライループで頻繁にアクセスな状況が起きる・・■ Mediation側の確率に偏り無ければ別Ad表示されればOKすが・・
● Android JUnit で Parameterized test case○ http://kokufu.blogspot.jp/2012/07/android-junit-
parameterized-test-case.html
○ サンプルも動かせなかった><■ 2.3.3以降対応らしいけど、Xoomでダメ・・
(RuntimeExceptionがでる■ でも2系のテストが普通に出来ないのは厳しめ
か。。。
● Native Driverでのテスト○ テストプロジェクト側がjavaプロジェクトでないと動かない
というのに気づかなくてハマった><
実機でテストしているとLOCKやKEYGUARDがかかってしまう問題
○ NativeDriverのサンプルのように
■ 検証側のAndroidManifest.xml側に
はどうなんでしょう??(有識者の知恵を聞きたいかも<この状態でもUSB等で給電していなければ画面ロックがかかってしまったり
<uses-permission android:name="android.permission.WEAK_LOCK" /><uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
実際には)● 画面を ON のままにする方法
○ http://android.keicode.com/basics/how-to-keep-screen-on.php● WakeLockを取得し、Sleep状態からWake状態へ遷移する
○ http://techbooster.jpn.org/andriod/application/4429/あたりの対応が必要らしいのですが・・本体のコードはあまり弄りたくないかな・・(権限も含めて
emmaを使った実機テスト● ant emma debug install test とか実行すると
○ WARNING: Code Coverage is currently only supported on the emulator and rooted devices.
てのがでる。実機でのテストが多いのでちょっと微妙・・(Ad系のテストは、端末情報を取得している面があり 基本実機で確認してほしいというお話はあったりとか)
● ここら辺の話は● @3a3k さんが
○ 今更ながらAntでAndroidのTestを実行してみる■ http://3a3k.blogspot.jp/2012/01/antandroidtest.html
で書かれたりしています● あとはメインのbuild.xmlを弄るといい話も
○ http://stackoverflow.com/questions/2762665/how-to-use-emma-code-coverage-in-android
● 他の参考ページ○ http://d.hatena.ne.jp/halts/20120201/p1
実行の仕方でエラーがでるテストも・・(謎
● OK:直接eclipse上からテスト右選択して実行
● NG:ant経由(勿論画面ロックはかかってない)■ TouchUtils.tapView(this,(View)target);
○ あたりで
○ java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
● ググると
○ AndroidのスクリーンロックをJenkinsでのビルド時に解除する■ http://d.hatena.ne.jp/makiczar/20111029/1319853201■ adb shell input keyevent 82
の話が出てくるのですが・・・?
● したがって、今回は● イケメン@sassy_watsonさんに教えて頂いたadb
経由で端末を指定してテスト回そうな形にしました○ 動かす設定はあとで末尾を見てね
○ http://developer.android.com/intl/ja/reference/android/test/InstrumentationTestRunner.html
〜雑話〜
と長々と書きましたが
● Mediation対応自体はIOSでの対応が切望される事が多い○ 理由としては、クリック単価率等が2−3円は違う
かららしい○ IOSユーザ:富裕層、購買意欲高○ Androidユーザ:ガラケーユーザと同じくタダで
端末手に入れたりした層(お金使わない)な分析されていたり(汗
● IPhone/IPad● スマートフォン(Android?)● ガラケーな分類が未だ一般的
・Ad広告を設定する場合、カテゴリ設定をする=>普通はエロは設定しない=>なんで出ちゃうの?
在庫無い時)・黒い画面が出てしまう
各社の対応)・Google =>GoogleのAdSenseの広告を出す・他社 =>黒い画面のまま か 自社広告か 担当の人が余って
いる広告をだそうとする(これがエロっぽかったりする事が多い)
だから実はソフト作っている人や会社に文句いってもどうにもならないんですね。それだけ日本が景気悪くなっていると言う事かも
エロ広告増えてる理由>
〜端末ごとテストで注意してる観点と遭遇した事〜
IS01> Android1.6固有の問題( if(Build.VERSION.SDK_INT>=11)等 の場合分けをしてもクラス直書きの関数を舐めてエラーになる <要別クラス )
AUスマートパス対応の時に必要。Medibaの最新版Ad(要target-7)を入れてしまうと動かないので要注意(グループ会社なのになんででしょうね<汗)
IS03>画面が小さいのに高解像度dpi算出されてしまうので if("KDDI".equals(Build.BRAND) && "IS03".equals(Build.MODEL))
辺りの場合分けは必須
GalaxyTab>基本的には問題ないのですが、電源入れているとうまく充電されないような?(気のせいか?Android Runtime発生するとなぜか本体ごと落ちる事多々
XOOM>Android3.0固有の問題に結構泣かされます(2系,4系で動いてもエラーが出る事が多々)。横向きにすると落ちるAd等もあったり(Adの中でぬるぽ)Android Runtimeが発生する=>要リセット必要が多々
layout指定しても部品が小さくなることがあり if( "MOTO".equals(Build.BRAND) && "MZ604".equals(Build.MODEL) { px*m_density (元の大きさ指定 px) ぐらいの大きさにレイアウトし直す必要があったりとか <場合によっては 2倍ぐらいとる必要あり
HTC Desire>画像をlayout.xml等でたくさん使用しているとOutOfMemoryが出やすい端末
ARROWS Z >高解像度の為か画面がやたら処理落ちする(OpenGL等でも駄目)デュアルコアで速いとメーカーが歌っている分ユーザさんから「なぜ遅いの?」な問い合わせが多い機種
Galaxy S1>0.05秒以下の効果音がなぜか鳴らない(ここはARROWS Z等も同じ)
Galaxy Nexus>基本的にエラーは無し。・横幅が普通の端末より広いのでレイアウト320dipとか固定にしていると横幅が足りない
・複雑なレイアウトでRelativeLayoutでレイアウトした時に画面が崩れる等があったくらい
ISW13HT >ソケット待ちで1個スレッド起こしている某アプリで、タッチやキー入力時にObject.wait(1) 等の同期Sleep入れないと一切反応を受け付けなかった端末。
005SH>
android:configChanges="keyboard|keyboardHidden"等のキーボード開閉イベントも拾っておく必要があり(webView等で弾かないとキーボード開閉した段階でViewがリフレッシュされて入力
がクリアされてしまう)
L-04C>キーボード開閉イベント有。SDカードにインストールするとすごく遅くなる機種
REGZA Phone,他のGalaxy,infobar,XPERIA辺りは基本的に速度面を別にしては問題でてない感じ。
〜完全なおまけ〜
groovyスクリプトの活用
● groovy eclipse-pluginのインストール○ インストールの話は下記の方のブログを参照○ @shinyaa31 [Java][Groovy][Eclipse]Java/Groovy
エンジニアのためのEclipse開発環境構築/テスト実践方法まとめ■ http://d.hatena.ne.
jp/absj31/20120803/1344114579#eclipse_groovyprog
○ @waman10daGroovy Eclipse Plugin (1):インストールと設定
■ http://d.hatena.ne.jp/waman/20090424/1240603561
● ただAndroid Projectで使うのは問題有り○ プログラミングGroovyでも書いててあるけど
「Groovy Project」で使える○ eclipse上から便利スクリプトとして使いたい用
途にはちょっと■ でも一応groovyファイルの色分け等はされるので全く
無駄ではないですよ!
■ =>
○ 外部ツールに登録して使えばいいよね!■ groovy自体は別途要インストール
外部ツールの設定(1)
外部ツールの設定(2)
groovyファイルを選択してお気に入りのgroovyを実行
どんな利用が考えられるか?
● usbで複数端末繋がってる全部の端末に一度にインストールできると便利だよね○ build.xml は端末1つ時のみ対応〜><○ 複数端末つないで開発な環境だとすごく面倒><
で作ってみた
● https://gist.github.com/3669015○ 以前 build.xml に手を入れて作っていた物の拡
張版です。次のようなアドバイスをウケたので。基本的にbuild.xmlは更新かかる可能性があるので、手を入れない方が良いらしい
スクリプトの補足)
● eclipse3.7上では○ ant.importBuild 'build.xml'
■ が上手く動きません
○ eclipseに含まれているantが1.7ベースなのでそちらが参照されてしまう
● 従って下記のような迂回した形になります
def antFile = new File("./build.xml")def project = new Project()project.init()ProjectHelper.configureProject(project, antFile);project.executeTargets(['clean', 'release'] as Vector)
● AntBuilderのoutputproperty等の値がキャッシュされ変更不可なのであえてカウンターで別名をつけて状態を取得してます
cnt++cmd = "-s $it install -r $file"ant.exec(outputproperty:"cmdOut$cnt", errorproperty: "cmdErr$cnt", resultproperty:"cmdExit$cnt", dir:".", failonerror: "false", executable: "${adb_home}/adb") { arg(line:cmd) }println "[$cmd]<" + ant.project.properties."cmdExit$cnt" + ">=" + ant.project.properties."cmdOut$cnt"
このスクリプトだとprintlnでSystem.outに出力してますが、下記のように囲んでしまうのも手
def stdOut = System.out; // save old System.outdef newFileOutputStream = new FileOutputStream("log_${new Date().format("yyyy-MM-dd-HH-mm")}.txt", true);def newOutputFilePrintSteam = new PrintStream(newFileOutputStream); System.setOut(newOutputFilePrintSteam);
//処理
System.setOut(stdOut);
build.xmlの作り方の復習
● ライブラリプロジェクト○ android update project -p ./
● メインプロジェクト○ android update project -p ./ -l ../AdManager
● テストプロジェクト○ android update test-project -m ../template_canvas -p
./
(ただこの場合、build.xmlでテストを動かした時にライブラリプロジェクトが見えないようで手動で追加したのでコマンド的には足りないかも)
ライブラリプロジェクト AdManager
メインプロジェクト template_canvas
テストプロジェクト template_canvas_test
● 認証キーが無い場合● keytool -genkey -v -keyalg RSA -keystore ./debug.
keystore -alias androiddebugkey -validity 10000○ android/android で作るイメージで想定
● local.propertiesを編集します
# 自分の環境が違う場合はsdk.dirを修正する事
sdk.dir=/Users/◎◎/android-sdk-macosx
key.store=debug.keystorekey.alias=androiddebugkeykey.store.password=androidkey.alias.password=androidrelease.app.name=hellorelease.app.version=v01
さてお気づきの方だと
● なんでGradle eclipse Pluginでやらんの?○ という話が出ると思いますが
■ =>
○ なんかSTSじゃ無いと現在まともに動かんらしい〜 ><
● で外部ツールで直接実行は?○ 正体不明のエラーが出る
備考:eclipse上でbuild.xmlを動かすには
● UTF-8にする必要があり(例はeclipse3.7での場合
SJISでプロジェクトを作ってた場合(for Mac
● MultiTextConverterで変換
○ http://www.rk-k.com/software/mtc○ 下記設定をしてsrcフォルダをD&D
ここははずす
groovyに多少でも興味を持った方は
● 有名G*ブロガー @orange_cloverさんの○ 2012年08月 Groovyist/G*のあれやこれ
■ http://d.hatena.ne.jp/orangeclover/20120902/1346573067
あたりを参照されると良いでしょう
groovyHelp● groovyとjava-docのHelp検索ツール
○ http://syboos.jp/oss/doc/groovyhelp.html○ java7u6以上が必要○ macで動かすときはgroovyhelpのシェルを修正した
■ 検索とか微妙に動かなかったのでwin専用かも?
#!/bin/bash
export GROOVYHELP_JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_07.jdk/Contents/Home
if [ -d "$GROOVYHELP_JAVA_HOME" ]; then JAVA_EXE="$GROOVYHELP_JAVA_HOME/bin/java";elif [ -d "$JAVA_HOME" ]; then JAVA_EXE="$JAVA_HOME/bin/java";else JAVA_EXE="java";fi
JAVA_EXE="`echo "$JAVA_EXE" | sed 's/\\\\/\//g'`";
chmod -R 755 lib;eval "`"$JAVA_EXE" -jar ./lib/groovyhelp_launcher.jar "$JAVA_EXE"`";