1. Service服務詳解以及怎麼使service服務不被殺死
Services
服務是一個應用程序組件,可以在後台執行長時間運行的操作,不提供用戶界面。一個應用程序組件可以啟動一個服務,它將繼續在後台運行,即使用戶切換到另一個應用程序。此外,一個組件可以綁定到一個服務與它交互,甚至執行進程間通信(IPC)。例如,一個服務可能處理網路通信,播放音樂,執行文件I/O,或與一個內容提供者交互,都在後台執行。
一個服務本質上講有兩種形式:
Started 啟動的
started 形式的服務是指當一個應用組件(比如 activity )通過startService()方法開啟的服務。一旦開啟,該服務就可以 無限期 地在後台運行,哪怕開啟它的組件被銷毀掉。
通常,開啟的服務執行一個單獨的操作且並不向調用者返回一個結果。
比如,可能從網路進行下載或者上傳一個文件。當任務完成,服務就該自我停止。
Bound 綁定的
bound 形式的服務是指一個應用組件通過調用 bindService() 方法與服務綁定。一個綁定的服務提供一個客戶-服務端介面,以允許組件與服務交互,發送請求,獲得結果,甚至執行進程間通信。一個綁定的服務只和與其綁定的組件同時運行。多個組件可以同時綁定到一個服務,但當全部接觸綁定後,服務就被銷毀。
雖然分這兩類,但是一個服務可以同時使用這兩種方式——可以用 started 無限期的運行,同時允許綁定。只需要在服務中實現兩個回調方法: onStartCommand() 允許組件開啟服務, onBind() 允許綁定。
不論應用程序是怎麼起服務的, 任何 應用程序都可以用這個服務。同樣的,任何組件可以使用一個 Activity 通過傳遞 Intent 開啟服務。你也可以在配置文件設置服務為私有來防止其他應用訪問該服務。
注意: 一個服務在進程中的主線程運行——一個服務 不會 創建自己的線程,也 不會 在另外的進程運行(除非另外指定)。這意味著,如果服務需要做一些頻繁佔用CPU的工作或者會發生阻塞的操作,你需要在服務中另開線程執行任務。這可以降低產生ANR的風險,提高用戶體驗。
基礎
創建一個服務需要建立一個 Service 相關的子類,然後需要實現一些回調方法,好在不同的生命周期內做對應處理和綁定服務,比較重要的方法如下:
onStartCommand()
當其他組件,如 activity 請求服務啟動時,系統會調用這個方法。一旦這個方法執行,服務就開始並且無限期的執行。如果實現這個方法,當這個服務完成任務後,需要你來調用 stopSelf() 或者 stopService() 停掉服務。如果只想提供綁定,不需要自己實現這個方法。
onBind()
當有其他組件想通過 bindService() 方法綁定這個服務時系統就會調用此方法。在實現的方法裡面,必須添加一個供客戶端使用的介面通過返回一個 IBinder 來與服務通信,這個方法必須實現。當然不想允許綁定的話,返回 null 即可。
onCreate()
服務第一次建立的時候會調用這個方法,執行一次性設置程序,在上面2個方法執行前調用。如果服務已存在,則不執行該方法。
onDestroy()
服務不再使用則使用該方法。服務應該實現這個方法來清理諸如線程,注冊的監聽器等資源。這是最後調用的方法。
安卓系統只會在內存佔用很高,必須恢復系統資源供當前運行程序的情況下強制停掉一個運行中的服務。如果服務綁定在當前運行的程序中,就幾乎不會被殺掉,如果服務聲明了在前台運行(其實在後台,只是給系統一個錯的信息來提高優先順序),就幾乎不會被殺掉。另外,如果一個服務正在運行,且運行了很久,系統就會根據運行時間把其排在後台任務列表的後面,則這個服務很容易被殺掉。根據onStartCommand() 的返回值設置,服務被殺掉後仍可以在資源充足的條件下立即重啟。
是用一個服務好還是開一個線程好
一個服務就是一個可以忽略交互,在後台獨立運行的組件,如果你需要這樣就用服務
如果你需要在用戶與程序交互時在主線程外執行任務,那就開個線程吧。
比如想播放音樂,但只在程序運行時播放,你可能在 onCreate() 開一個線程,在 onStart() 中開啟它,在 onStop() 停止它。也可以考慮使用 AsyncTask 或者HandlerThread 取代一般的線程。
記住,如果使用一個服務,它還是默認在主線程中運行,如果會發生阻塞,還是要在服務中另開線程的。
在 manifest 文件聲明服務
要使用服務就必須在 manifest 文件聲明要用的所有服務,只用在<application> 標簽內添加子標簽 <service> 即可。
<manifest ...>
...
<application ...>
<service android:name=".ExampleService"
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:icon="drawable resource"
android:permission="string"
android:process="string" >
...
</service>
</application>
</manifest>
下面對 service 標簽屬性做說明
android:name
你所編寫的服務類的類名,可填寫完整名稱,包名+類名,如com.example.test.ServiceA ,也可以忽略包名,用 . 開頭,如 .ServiceA,因為在 manifest 文件開頭會定義包名,它會自己引用。
一旦你發布應用,你就不能改這個名字(除非設置 android:exported="false"),另外 name 沒有默認值,必須定義。
android:enabled
是否可以被系統實例化,默認為 true
因為父標簽 <application> 也有 enable 屬性,所以必須兩個都為默認值true 的情況下服務才會被激活,否則不會激活。
android:exported
其他應用能否訪問該服務,如果不能,則只有本應用或有相同用戶ID的應用能訪問。當然除了該屬性也可以在下面 permission 中限制其他應用訪問本服務。
這個默認值與服務是否包含意圖過濾器 intent filters 有關。如果一個也沒有則為 false
android:isolatedProcess
設置 true 意味著,服務會在一個特殊的進程下運行,這個進程與系統其他進程分開且沒有自己的許可權。與其通信的唯一途徑是通過服務的API(binding and starting)。
android:label
可以顯示給用戶的服務名稱。如果沒設置,就用 <application> 的 lable 。不管怎樣,這個值是所有服務的意圖過濾器的默認 lable 。定義盡量用對字元串資源的引用。
android:icon
類似 label ,是圖標,盡量用 drawable 資源的引用定義。
android:permission
是一個實體必須要運行或綁定一個服務的許可權。如果沒有許可權,startService() , bindService() 或 stopService() 方法將不執行,Intent 也不會傳遞到服務。
如果屬性未設置,會由 <application> 許可權設置情況應用到服務。如果兩者都未設置,服務就不受許可權保護。
android:process
服務運行所在的進程名。通常為默認為應用程序所在的進程,與包名同名。<application> 元素的屬性 process 可以設置不同的進程名,當然組件也可設置自己的進程覆蓋應用的設置。
如果名稱設置為冒號 : 開頭,一個對應用程序私有的新進程會在需要時和運行到這個進程時建立。如果名稱為小寫字母開頭,服務會在一個相同名字的全局進程運行,如果有許可權這樣的話。這允許不同應用程序的組件可以分享一個進程,減少了資源的使用。
創建「啟動的」服務
啟動的(started)服務由 startService(Intent) 方法啟動,在服務中的 onStartCommand()方法里獲得 Intent 信息。關閉則由服務自己的方法 stopSelf() 或者由啟動服務的地方調用 stopService(Intent) 方法來關閉。並不會因為啟動服務的應用程序銷毀而關閉。
示例,一個應用需要保存數據到遠程資料庫,這時啟動一個服務,通過創建啟動的服務給服務傳遞數據,由服務執行保存行為,行為結束再自我銷毀。因為服務跟啟動它的應用在一個進程的主線程中,所以對於耗時的操作要起一個新的線程去做。
//activity中
Intent intent = new Intent(MainActivity.this, ServiceA.class);
intent.putExtra("name", strName);
startService(intent);
//service中
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
// 獲取數據
String strName = intent.getStringExtra("name");
// ... 資料庫操作
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
耗時的操作
}
}).run();
return Service.START_STICKY;
}
寫服務有2種,繼承 service 或者 IntentService 。後者是前者的子類。前者包含上面介紹的各種方法,用於普通的服務。後者可以自己開一個工作線程一個接一個處理多個請求。
繼承IntentService
大多數服務不需要同時處理多個請求,繼承 IntentService 是最好的選擇
IntentService處理流程
創建默認的一個 worker 線程處理傳遞給 onStartCommand() 的所有 intent ,不佔據應用的主線程
創建一個工作隊列一次傳遞一個 intent 到你實現的 onHandleIntent() 方法,避免了多線程
在所以啟動請求被處理後自動關閉服務,不需要調用 stopSelf()
默認提供 onBind() 的實現,並返回 null
默認提供 onStartCommand() 的實現,實現發送 intent 到工作隊列再到你的onHandleIntent() 方法實現。
這些都加入到 IntentService 中了,你需要做的就是實現構造方法和onHandleIntent() ,如下:
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}
如果需要重寫其他回調方法,如 onCreate() , onStartCommand() 等,一定要調用super() 方法,保證 IntentService 正確處理 worker 線程,只有 onHandleIntent()和 onBind() 不需要這樣。如:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId);
}
繼承Service
繼承 Service 就可以實現對請求多線程的處理,前面介紹了 service 的生命周期,可以按照生命周期實現方法。就不放示例了。
onStartCommand() 的返回值
返回一個整型值,用來描述系統在殺掉服務後是否要繼續啟動服務,返回值有三種:
START_NOT_STICKY
系統不重新創建服務,除非有將要傳遞來的 intent 。這是最安全的選項,可以避免在不必要的時候運行服務。
START_STICKY
系統重新創建服務並且調用 onStartCommand() 方法,但並不會傳遞最後一次傳遞的 intent ,只是傳遞一個空的 intent 。除非存在將要傳遞來的 intent ,那麼就會傳遞這些 intent 。這個適合播放器一類的服務,不需要執行命令,只需要獨自運行,等待任務。
START_REDELIVER_INTENT
系統重新創建服務並且調用 onStartCommand() 方法,傳遞最後一次傳遞的intent 。其餘存在的需要傳遞的intent會按順序傳遞進來。這適合像下載一樣的服務,立即恢復,積極執行。
如果想從服務獲得結果,可以用廣播來處理
創建「綁定的」服務
用 bindService() 方法將應用組件綁定到服務,建立一個長時間保持的聯系。
如果需要在 activity 或其他組件和服務交互或者通過進程間通信給其他應用程序提供本應用的功能,就需要綁定的服務。
建立一個綁定的服務需要實現 onBind() 方法返回一個定義了與服務通信介面的IBinder 對象。其他應用程序組件可以調用 bindService() 方法獲取介面並且調用服務上的方法。
創建一個綁定的服務,第一件事就是定義一個說明客戶端與服務通信方式的介面。這個介面必須是 IBinder 的實現,並且必須要從 onBind() 方法返回。一旦客戶端接收到了 IBinder ,就可以通過這個介面進行交互。
多個客戶端可以綁定到一個服務,可以用 unbindService() 方法解除綁定,當沒有組件綁定在服務上,這個服務就會被銷毀。
//activity中
private ServiceConnection connB = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.v(tag, "Service B disconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.v(tag, "Service B connected");
MyBinderB binder = (MyBinderB) service;
ServiceB SB = binder.getService();
SB.showLog();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent a = new Intent(MainActivity.this, ServiceB.class);
bindService(a, connB, BIND_AUTO_CREATE);
}
}
//ServiceB
public class ServiceB extends Service {
public void showLog() {
Log.i(tag, "serviceB-->showLog()");
}
public class MyBinderB extends Binder {
public ServiceB getService() {
return ServiceB.this;
}
}
private MyBinderB myBinderB = new MyBinderB();
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return myBinderB;
}
}
啟動前台服務
前台服務是被認為是用戶已知的正在運行的服務,當系統需要釋放內存時不會優先殺掉該進程。前台進程必須發一個 notification 在狀態欄中顯示,直到進程被殺死。因為前台服務會一直消耗一部分資源,但不像一般服務那樣會在需要的時候被殺掉,所以為了能節約資源,保護電池壽命,一定要在建前台服務的時候發notification ,提示用戶。當然,系統提供的方法就是必須有 notification 參數的,所以不要想著怎麼把 notification 隱藏掉。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification noti = new Notification.Builder(this)
.setContentTitle("Title")
.setContentText("Message")
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pendingIntent)
.build();
startForeground(12346, noti);
return Service.START_STICKY;
}
startForeground() 方法就是將服務設為前台服務。參數12346就是這個通知唯一的id,只要不為0即可。
2. 怎麼在 service 層控制事務
你好,很高興回答你的問題。
Spring的事務管理本身是基於aop的原理,在執行service方法之前開啟事務,執行service方法之後提交事務,如果遇到異常,則回滾。
要不使用Spring自己實現,那就是把上述的邏輯自己實現一遍。
如果有幫助到你,請點擊採納。
3. 蘋果手機service怎麼用語音打開
方法如下:1、打開手機桌面上的設置。2、找到並點擊進入Siri與搜索。3、打開用「嘿Siri」喚醒和按下側邊按鈕使用Siri右側的開關後即可語音喚醒。
iPhone中的siri功能在第一次退出的時候,讓世界所有的人都為這種人機交互的方式感到震驚,只是幾年過去了,siri依舊還是沒有突破,不過現在有一個功能,就是可以直接通過語音來喚醒siri。
4. Android中如何啟用Service,如何停用Service
• Context.startService()
• Context.bindService()
1. 在同一個應用任何地方調用 startService() 方法就能啟動 Service 了,然後系統會回調 Service 類的
onCreate() 以及 onStart() 方法。這樣啟動的 Service 會一直運行在後台,直到
Context.stopService() 或者 selfStop() 方法被調用。另外如果一個 Service 已經被啟動,其他代碼再試圖調用
startService() 方法,是不會執行 onCreate() 的,但會重新執行一次 onStart() 。
2. 另外一種 bindService() 方法的意思是,把這個 Service 和調用 Service
的客戶類綁起來,如果調用這個客戶類被銷毀,Service 也會被銷毀。用這個方法的一個好處是,bindService() 方法執行後
Service 會回調上邊提到的 onBind() 方發,你可以從這里返回一個實現了 IBind
介面的類,在客戶端操作這個類就能和這個服務通信了,比如得到 Service 運行的狀態或其他操作。如果 Service
還沒有運行,使用這個方法啟動 Service 就會 onCreate() 方法而不會調用 onStart()。
總結:
1.
startService()的目的是回調onStart()方法,onCreate()
方法是在Service不存在的時候調用的,如果Service存在(例如之前調用了bindService,那麼Service的onCreate方法
已經調用了)那麼startService()將跳過onCreate() 方法。
2.
bindService()目的是回調onBind()方法,它的作用是在Service和調用者之間建立一個橋梁,並不負責更多的工作(例如一個
Service需要連接伺服器的操作),一般使用bindService來綁定到一個現有的Service(即通過StartService啟動的服
務)。
由於Service 的onStart()方法只有在startService()啟動Service的情況下才調用,故使用onStart()的時候要注意這點。
5. 什麼是Service以及描述下它的生命周期。Service有哪些啟動方法,有什麼區別,怎樣停用Service
onBind和onUnbind。 通常有兩種方式啟動一個Service,他們對Service生命周期的影響是不一樣的。 1 通過startService Service會經歷 onCreate 到onStart,然後處於運行狀態,stopService的時候調用onDestroy方法。 如果是調用者自己直接退出而沒有調用stopService的話,Service會一直在後台運行。 2 通過bindService Service會運行onCreate,然後是調用onBind, 這個時候調用者和Service綁定在一起。調用者退出了,Srevice就會調用onUnbind->onDestroyed方法。 所謂綁定在一起就共存亡了。調用者也可以通過調用unbindService方法來停止服務,這時候Srevice就會調用onUnbind->onDestroyed方法。 一個原則是Service的onCreate的方法只會被調用一次,就是你無論多少次的startService又bindService,Service只被創建一次。 如果先是bind了,那麼start的時候就直接運行Service的onStart方法,如果先是start,那麼bind的時候就直接運行onBind方法。 如果service運行期間調用了bindService,這時候再調用stopService的話,service是不會調用onDestroy方法的,service就stop不掉了,只能先UnbindService, 再StopService。 如果一個service通過startService 被start之後,多次調用startService 的話,service會多次調用onStart方法。多次調用stopService的話,service只會調用一次onDestroyed方法。 如果一個service通過bindService被start之後,多次調用bindService的話,service只會調用一次onBind方法。 多次調用unbindService的話會拋出異常。 擁有service的進程具有較高的優先順序 官方文檔告訴我們,Android系統會盡量保持擁有service的進程運行,只要在該service已經被啟動(start)或者客戶端連接(bindService)到它。當內存不足時,需要保持,擁有service的進程具有較高的優先順序。 1. 如果service正在調用onCreate, onStartCommand或者onDestory方法,那麼用於當前service的進程相當於前台進程以避免被killed。 2. 如果當前service已經被啟動(start),擁有它的進程則比那些用戶可見的進程優先順序低一些,但是比那些不可見的進程更重要,這就意味著service一般不會被killed. 3. 如果客戶端已經連接到service (bindService),那麼擁有Service的進程則擁有最高的優先順序,可以認為service是可見的。 4. 如果service可以使用startForeground(int, Notification)方法來將service設置為前台狀態,那麼系統就認為是對用戶可見的,並不會在內存不足時killed。 如果有其他的應用組件作為Service,Activity等運行在相同的進程中,那麼將會增加該進程的重要性。
6. Android中怎麼啟動關閉Service及功能解釋
啟動:
//首先注冊服務
<service
android:name="com.wangdeyu.service.MusicService"
android:exported="false" >
<intent-filter>
<action android:name="com.abc" />
</intent-filter>
</service>
//啟動服務
Intent service=new Intent(" com.abc");
startService(service);
//Service生命周期
①onCreate() 創建Service
②onStart(Intent intent, int startId) 啟動Service
③onDestroy() 銷毀Service
//關閉服務
stopService(service);
Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy
我們有兩種方式啟動一個Service,他們對Service生命周期的影響是不一樣的。
1 通過startService,就是上面這種
Service會經歷 onCreate --> onStart
stopService的時候直接onDestroy
如果是 調用者 直接退出而沒有調用stopService的話,Service會一直在後台運行。
下次調用者再起來仍然可以stopService。
2 通過bindService
Service只會運行onCreate, 這個時候 調用者和Service綁定在一起
調用者退出了,Srevice就會調用onUnbind-->onDestroyed
所謂綁定在一起就共存亡了。
注意:Service的onCreate的方法只會被調用一次,
就是你無論多少次的startService又 bindService,Service只被創建一次。
如果先是bind了,那麼start的時候就直接運行Service的onStart方法,
如果先是start,那麼bind的時候就直接運行onBind方法。如果你先bind上了,就stop不掉了,
只能先UnbindService, 再StopService,所以是先start還是先bind行為是有區別的。
Android中的服務和windows中的服務是類似的東西,服務一般沒有用戶操作界面,它運行於系統中不容易被用戶發覺,可以使用它開發如監控之類的程序。
服務不能自己運行,需要通過調用Context.startService()或Context.bindService()方法啟動服務。
這兩個方法都可以啟動Service,但是它們的使用場合有所不同。使用startService()方法啟用服務,調用者與服務之間沒有關連,
即使調用者退出了,服務仍然運行。使用bindService()方法啟用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有「不求同時生,必須同時死」的特點。
如果打算採用Context.startService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,
接著調用onStart()方法。如果調用startService()方法前服務已經被創建,多次調用startService()方法並不會導致多次創建服務,
但會導致多次調用onStart()方法。採用startService()方法啟動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。
如果打算採用Context.bindService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,
接著調用onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統就會先調用服務的onUnbind()方法,
接著調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,
多次調用bindService()方法並不會導致多次創建服務及綁定(也就是說onCreate()和onBind()方法並不會被多次調用)。
如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,調用該方法也會導致系統調用服務的onUnbind()-->onDestroy()方法.
7. android 怎麼調用service里的方法
直接傳activity 引用肯定是不行的, 最簡單的是 用靜態全局變數 ,不過不推薦。 所以只能復雜一點 ,不能service可以直接調用activity ,只能傳消息給activity ,讓activity 執行特定的方法。 就是 service start activity 。 而activity 設置為 single instance ,在newIntent 方法 裡面 處理 傳入消息。 還有一個方法就是activity 裡面定義 一個 內部類 broadcast ,然後 service 調用sendbraoadcast , broadcast 再調用 activity 方法。
8. webservice怎麼使用
通過添加WEB引用的方式調用,首先添加WEB引用,通過URL指向WEBSERVICE,
指定WEB引用名,假設為KK;
示例:
kk.WebService n = new kk.WebService();
string ss=n.HelloWorld();
二、WebService在前台頁面的JS 調用方法
1、首先通過下面的方法把Webservice在前台引用進來
<asp:ScriptManager runat="server">
<Services>
<asp:ServiceReference Path="WebService.asmx" InlineScript="True" />
</Services>
</asp:ScriptManager>
2、然後就可以通過JS程序進行調用,示例如下:
<script type="text/jscript">
function a()
{
WebService.HelloWorld(onresult);
}
//這里的onresult是回調函數
function onresult(result)
{
alert(result);
}
function b()
{
WebService.add(1,2,onreturn)
}
function onreturn(result)
{
alert(result);
}
//下面的'context'是上下文,可以通過回到函數通過重載的方式獲得;
function c()
{
WebService.div(1,1,onresultC,onerror,'context');
}
function onresultC(res,c)
{
alert(res);
alert(c);
}
//onerror是獲得異常信息的回調函數,下面給出了獲得異常信息的方法
function onerror(error)
{
var a="";
a=String.format("獲取伺服器端異常的具體類型:{0}\t\n獲取詳細的異常描述信息:{1}\t\n獲取造成異常的:{2}\t\n獲取伺服器端異常的堆棧
跟蹤信息:{3}\t\n獲取一個布爾值,表示異常是否是由於網路連接超時造成的{4}",
error.get_exceptionType(),
error.get_message(),
error.get_statusCode(),
error.get_stackTrace(),
error.get_timedOut())
alert(a);
}
a();
b();
c();
</script>