From ce878bef710c6d1e6881949c82b1293fb8435715 Mon Sep 17 00:00:00 2001 From: Scott Main <> Date: Sun, 26 Apr 2009 15:51:58 -0700 Subject: [PATCH] AI 147804: add new doc about Dialogs BUG=1800118 Automated import of CL 147804 --- docs/html/guide/topics/ui/dialogs.jd | 650 ++++++++++++++++++ docs/html/images/dialog_buttons.png | Bin 0 -> 3701 bytes docs/html/images/dialog_custom.png | Bin 0 -> 4018 bytes docs/html/images/dialog_list.png | Bin 0 -> 3830 bytes docs/html/images/dialog_progress_bar.png | Bin 0 -> 2562 bytes docs/html/images/dialog_progress_spinning.png | Bin 0 -> 2648 bytes docs/html/images/dialog_singlechoicelist.png | Bin 0 -> 5071 bytes 7 files changed, 650 insertions(+) create mode 100644 docs/html/guide/topics/ui/dialogs.jd create mode 100755 docs/html/images/dialog_buttons.png create mode 100755 docs/html/images/dialog_custom.png create mode 100755 docs/html/images/dialog_list.png create mode 100755 docs/html/images/dialog_progress_bar.png create mode 100755 docs/html/images/dialog_progress_spinning.png create mode 100755 docs/html/images/dialog_singlechoicelist.png diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd new file mode 100644 index 0000000000000..c0c0b1bc58da4 --- /dev/null +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -0,0 +1,650 @@ +page.title=Creating Dialogs +parent.title=User Interface +parent.link=index.html +@jd:body + +
A dialog is usually a small window that appears in front of the current Activity. +The underlying Activity loses focus and the dialog accepts all user interaction. +Dialogs are normally used +for notifications and short activities that directly relate to the application in progress.
+ +The Android API supports the following types of {@link android.app.Dialog} objects:
+If you would like to customize your own dialog, you can extend the +base {@link android.app.Dialog} object or any of the subclasses listed above and define a new layout. +See the section on Creating a Custom Dialog below.
+ + +A dialog is always created and displayed as a part of an {@link android.app.Activity}. +You should normally create dialogs from within your Activity's +{@link android.app.Activity#onCreateDialog(int)} callback method. +When you use this callback, the Android system automatically manages the state of +each dialog and hooks them to the Activity, effectively making it the "owner" of each dialog. +As such, each dialog inherits certain properties from the Activity. For example, when a dialog +is open, the Menu key reveals the options menu defined for the Activity and the volume +keys modify the audio stream used by the Activity.
+ +Note: If you decide to create a dialog outside of the
+onCreateDialog() method, it will not be attached to an Activity. You can, however,
+attach it to an Activity with {@link android.app.Dialog#setOwnerActivity(Activity)}.
When you want to show a dialog, call +{@link android.app.Activity#showDialog(int)} and pass it an integer that uniquely identifies the +dialog that you want to display.
+ +When a dialog is requested for the first time, Android calls +{@link android.app.Activity#onCreateDialog(int)} from your Activity, which is +where you should instantiate the {@link android.app.Dialog}. This callback method +is passed the same ID that you passed to {@link android.app.Activity#showDialog(int)}. +After you create the Dialog, return the object at the end of the method.
+ +Before the dialog is displayed, Android also calls the optional callback method +{@link android.app.Activity#onPrepareDialog(int,Dialog)}. Define this method if you want to change +any properties of the dialog each time it is opened. This method is called +every time a dialog is opened, whereas {@link android.app.Activity#onCreateDialog(int)} is only +called the very first time a dialog is opened. If you don't define +{@link android.app.Activity#onPrepareDialog(int,Dialog) onPrepareDialog()}, then the dialog will +remain the same as it was the previous time it was opened. This method is also passed the dialog's +ID, along with the Dialog object you created in {@link android.app.Activity#onCreateDialog(int) +onCreateDialog()}.
+ +The best way to define the {@link android.app.Activity#onCreateDialog(int)} and +{@link android.app.Activity#onPrepareDialog(int,Dialog)} callback methods is with a +switch statement that checks the id parameter that's passed into the method. +Each case should check for a unique dialog ID and then create and define the respective Dialog. +For example, imagine a game that uses two different dialogs: one to indicate that the game +has paused and another to indicate that the game is over. First, define an integer ID for +each dialog:
++static final int DIALOG_PAUSED_ID = 0; +static final int DIALOG_GAMEOVER_ID = 1; ++ +
Then, define the {@link android.app.Activity#onCreateDialog(int)} callback with a +switch case for each ID:
+
+protected Dialog onCreateDialog(int id) {
+ Dialog dialog;
+ switch(id) {
+ case DIALOG_PAUSED_ID:
+ // do the work to define the pause Dialog
+ break;
+ case DIALOG_GAMEOVER_ID:
+ // do the work to define the game over Dialog
+ break;
+ default:
+ dialog = null;
+ }
+ return dialog;
+}
+
+
+Note: In this example, there's no code inside +the case statements because the procedure for defining your Dialog is outside the scope +of this section. See the section below about Creating an AlertDialog, +offers code suitable for this example.
+ +When it's time to show one of the dialogs, call {@link android.app.Activity#showDialog(int)} +with the ID of a dialog:
++showDialog(DIALOG_PAUSED_ID); ++ + +
When you're ready to close your dialog, you can dismiss it by calling +{@link android.app.Dialog#dismiss()} on the Dialog object. +If necessary, you can also call {@link android.app.Activity#dismissDialog(int)} from the +Activity, which effectively calls {@link android.app.Dialog#dismiss()} on the +Dialog for you.
+ +If you are using {@link android.app.Activity#onCreateDialog(int)} to manage the state +of your dialogs (as discussed in the previous section), then every time your dialog is +dismissed, the state of the Dialog +object is retained by the Activity. If you decide that you will no longer need this object or +it's important that the state is cleared, then you should call +{@link android.app.Activity#removeDialog(int)}. This will remove any internal references +to the object and if the dialog is showing, it will dismiss it.
+ +If you'd like your applcation to perform some procedures the moment that a dialog is dismissed, +then you should attach an on-dismiss listener to your Dialog.
+ +First define the {@link android.content.DialogInterface.OnDismissListener} interface. +This interface has just one method, +{@link android.content.DialogInterface.OnDismissListener#onDismiss(DialogInterface)}, which +will be called when the dialog is dismissed. +Then simply pass your OnDismissListener implementation to +{@link android.app.Dialog#setOnDismissListener(DialogInterface.OnDismissListener) +setOnDismissListener()}.
+ +However, note that dialogs can also be "cancelled." This is a special case that indicates +the dialog was explicitly cancelled by the user. This will occur if the user presses the +"back" button to close the dialog, or if the dialog explicitly calls {@link android.app.Dialog#cancel()} +(perhaps from a "Cancel" button in the dialog). When a dialog is cancelled, +the OnDismissListener will still be notified, but if you'd like to be informed that the dialog +was explicitly cancelled (and not dismissed normally), then you should register +an {@link android.content.DialogInterface.OnCancelListener} with +{@link android.app.Dialog#setOnCancelListener(DialogInterface.OnCancelListener) +setOnCancelListener()}.
+ + +An {@link android.app.AlertDialog} is an extension of the {@link android.app.Dialog} +class. It is capable of constructing most dialog user interfaces and is the suggested dialog type. +You should use it for dialogs that use any of the following features:
+To create an AlertDialog, use the {@link android.app.AlertDialog.Builder} subclass. +Get a Builder with {@link android.app.AlertDialog.Builder#AlertDialog.Builder(Context)} and +then use the class's public methods to define all of the +AlertDialog properties. After you're done with the Builder, retrieve the +AlertDialog object with {@link android.app.AlertDialog.Builder#create()}.
+ +The following topics show how to define various properties of the AlertDialog using the +AlertDialog.Builder class. If you use any of the following sample code inside your +{@link android.app.Activity#onCreateDialog(int) onCreateDialog()} callback method, +you can return the resulting Dialog object to display the dialog.
+ + +
+
+To create an AlertDialog with side-by-side buttons like the one shown in the screenshot to the right,
+use the set...Button() methods:
+AlertDialog.Builder builder = new AlertDialog.Builder(this);
+builder.setMessage("Are you sure you want to exit?")
+ .setCancelable(false)
+ .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ MyActivity.this.finish();
+ }
+ })
+ .setNegativeButton("No", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+AlertDialog alert = builder.create();
+
+
+First, add a message for the dialog with
+{@link android.app.AlertDialog.Builder#setMessage(CharSequence)}. Then, begin
+method-chaining and set the dialog
+to be not cancelable (so the user cannot close the dialog with the back button)
+with {@link android.app.AlertDialog.Builder#setCancelable(boolean)}. For each button,
+use one of the set...Button() methods, such as
+{@link android.app.AlertDialog.Builder#setPositiveButton(CharSequence,DialogInterface.OnClickListener)
+setPositiveButton()}, that accepts the name for the button and a
+{@link android.content.DialogInterface.OnClickListener} that defines the action to take
+when the user selects the button.
Note: You can only add one of each button type to the +AlertDialog. That is, you cannot have more than one "positive" button. This limits the number +of possible buttons to three: positive, neutral, and negative. These names are technically irrelevant to the +actual functionality of your buttons, but should help you keep track of which one does what.
+ + +
+
+To create an AlertDialog with a list of selectable items like the one shown to the right,
+use the setItems() method:
+final CharSequence[] items = {"Red", "Green", "Blue"};
+
+AlertDialog.Builder builder = new AlertDialog.Builder(this);
+builder.setTitle("Pick a color");
+builder.setItems(items, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
+ }
+});
+AlertDialog alert = builder.create();
+
+
+First, add a title to the dialog with +{@link android.app.AlertDialog.Builder#setTitle(CharSequence)}. +Then, add a list of selectable items with +{@link android.app.AlertDialog.Builder#setItems(CharSequence[],DialogInterface.OnClickListener) +setItems()}, which accepts the array of items to display and a +{@link android.content.DialogInterface.OnClickListener} that defines the action to take +when the user selects an item.
+ + +
+
+To create a list of multiple-choice items (checkboxes) or +single-choice items (radio buttons) inside the dialog, use the +{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String, +DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()} and +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} methods, respectively. +If you create one of these selectable lists in the +{@link android.app.Activity#onCreateDialog(int) onCreateDialog()} callback method, +Android manages the state of the list for you. As long as the Activity is active, +the dialog remembers the items that were previously selected, but when the user exits the +Activity, the selection is lost. + +
Note: To save the selection when the user leaves or +pauses the Activity, you must properly save and restore the setting throughout +the Activity Lifecycle. +To permanently save the selections, even when the Activity process is completely shutdown, +you need to save the settings +with one of the Data +Storage techniques.
+ +To create an AlertDialog with a list of single-choice items like the one shown to the right,
+use the same code from the previous example, but replace the setItems() method with
+{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
+setSingleChoiceItems()}:
+final CharSequence[] items = {"Red", "Green", "Blue"};
+
+AlertDialog.Builder builder = new AlertDialog.Builder(this);
+builder.setTitle("Pick a color");
+builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
+ }
+});
+AlertDialog alert = builder.create();
+
+
+The second parameter in the +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(CharSequence[],int,DialogInterface.OnClickListener) +setSingleChoiceItems()} method is an integer value for the checkedItem, which indicates the +zero-based list position of the default selected item. Use "-1" to indicate that no item should be +selected by default.
+ + +
+
+A {@link android.app.ProgressDialog} is an extension of the {@link android.app.AlertDialog} +class that can display a progress animation in the form of a spinning wheel, for a task with +progress that's undefined, or a progress bar, for a task that has a defined progression. +The dialog can also provide buttons, such as one to cancel a download.
+ +Opening a progress dialog can be as simple as calling +{@link android.app.ProgressDialog#show(Context,CharSequence,CharSequence) +ProgressDialog.show()}. For example, the progress dialog shown to the right can be +easily achieved without managing the dialog through the +{@link android.app.Activity#onCreateDialog(int)} callback, +as shown here:
+ ++ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", + "Loading. Please wait...", true); ++ +
The first parameter is the application {@link android.content.Context}, +the second is a title for the dialog (left empty), the third is the message, +and the last parameter is whether the progress +is indeterminate (this is only relevant when creating a progress bar, which is +discussed in the next section). +
+ +The default style of a progress dialog is the spinning wheel. +If you want to create a progress bar that shows the loading progress with granularity, +some more code is required, as discussed in the next section.
+ + +
+
+To show the progression with an animated progress bar:
+ +For example, your setup might look like this:
+
+ProgressDialog progressDialog;
+progressDialog = new ProgressDialog(mContext);
+progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+progressDialog.setMessage("Loading...");
+progressDialog.setCancelable(false);
+
+
+The setup is simple. Most of the code needed to create a progress dialog is actually +involved in the process that updates it. You might find that it's +necessary to create a second thread in your application for this work and then report the progress +back to the Activity's UI thread with a {@link android.os.Handler} object. +If you're not familiar with using additional +threads with a Handler, see the example Activity below that uses a second thread to +increment a progress dialog managed by the Activity.
+ + + + +
+ Example ProgressDialog with a second thread
+ This example uses a second thread to track the progress of a process (which actually just +counts up to 100). The thread sends a {@link android.os.Message} back to the main +Activity through a {@link android.os.Handler} each time progress is made. The main Activity then updates the +ProgressDialog.
+ +
+package com.example.progressdialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+public class NotificationTest extends Activity {
+ static final int PROGRESS_DIALOG = 0;
+ Button button;
+ ProgressThread progressThread;
+ ProgressDialog progressDialog;
+
+ /** Called when the activity is first created. */
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ // Setup the button that starts the progress dialog
+ button = (Button) findViewById(R.id.progressDialog);
+ button.setOnClickListener(new OnClickListener(){
+ public void onClick(View v) {
+ showDialog(PROGRESS_DIALOG);
+ }
+ });
+ }
+
+ protected Dialog onCreateDialog(int id) {
+ switch(id) {
+ case PROGRESS_DIALOG:
+ progressDialog = new ProgressDialog(NotificationTest.this);
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setMessage("Loading...");
+ progressThread = new ProgressThread(handler);
+ progressThread.start();
+ return progressDialog;
+ default:
+ return null;
+ }
+ }
+
+ // Define the Handler that receives messages from the thread and update the progress
+ final Handler handler = new Handler() {
+ public void handleMessage(Message msg) {
+ int total = msg.getData().getInt("total");
+ progressDialog.setProgress(total);
+ if (total >= 100){
+ dismissDialog(PROGRESS_DIALOG);
+ progressThread.setState(ProgressThread.STATE_DONE);
+ }
+ }
+ };
+
+ /** Nested class that performs progress calculations (counting) */
+ private class ProgressThread extends Thread {
+ Handler mHandler;
+ final static int STATE_DONE = 0;
+ final static int STATE_RUNNING = 1;
+ int mState;
+ int total;
+
+ ProgressThread(Handler h) {
+ mHandler = h;
+ }
+
+ public void run() {
+ mState = STATE_RUNNING;
+ total = 0;
+ while (mState == STATE_RUNNING) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ Log.e("ERROR", "Thread Interrupted");
+ }
+ Message msg = mHandler.obtainMessage();
+ Bundle b = new Bundle();
+ b.putInt("total", total);
+ msg.setData(b);
+ mHandler.sendMessage(msg);
+ total++;
+ }
+ }
+
+ /* sets the current state for the thread,
+ * used to stop the thread */
+ public void setState(int state) {
+ mState = state;
+ }
+ }
+}
+
+
+
+If you want a customized design for a dialog, you can create your own layout +for the dialog window with layout and widget elements. +After you've defined your layout, pass the root View object or +layout resource ID to {@link android.app.Dialog#setContentView(View)}.
+ +For example, to create the dialog shown to the right:
+ +custom_dialog.xml:
++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/layout_root" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:padding="10dp" + > + <ImageView android:id="@+id/image" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_marginRight="10dp" + /> + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:textColor="#FFF" + /> +</LinearLayout> ++ +
This XML defines an {@link android.widget.ImageView} and a {@link android.widget.TextView} + inside a {@link android.widget.LinearLayout}.
+
+Context mContext = getApplicationContext();
+Dialog dialog = new Dialog(mContext);
+
+dialog.setContentView(R.layout.custom_dialog);
+dialog.setTitle("Custom Dialog");
+
+TextView text = (TextView) dialog.findViewById(R.id.text);
+text.setText("Hello, this is a custom dialog!");
+ImageView image = (ImageView) dialog.findViewById(R.id.image);
+image.setImageResource(R.drawable.android);
+
+
+ After you instantiate the Dialog, set your custom layout as the dialog's content view with + {@link android.app.Dialog#setContentView(int)}, passing it the layout resource ID. + Now that the Dialog has a defined layout, you can capture View objects from the layout with + {@link android.app.Dialog#findViewById(int)} and modify their content.
+A dialog made with the base Dialog class must have a title. If you don't call +{@link android.app.Dialog#setTitle(CharSequence) setTitle()}, then the space used for the title +remains empty, but still visible. If you don't want +a title at all, then you should create your custom dialog using the +{@link android.app.AlertDialog} class. However, because an AlertDialog is created easiest with +the {@link android.app.AlertDialog.Builder} class, you do not have access to the +{@link android.app.Dialog#setContentView(int)} method used above. Instead, you must use +{@link android.app.AlertDialog.Builder#setView(View)}. This method accepts a {@link android.view.View} object, +so you need to inflate the layout's root View object from +XML.
+ +To inflate the XML layout, retrieve the {@link android.view.LayoutInflater} with +{@link android.app.Activity#getLayoutInflater()} +(or {@link android.content.Context#getSystemService(String) getSystemService()}), +and then call +{@link android.view.LayoutInflater#inflate(int, ViewGroup)}, where the first parameter +is the layout resource ID and the second is the ID of the root View. At this point, you can use +the inflated layout to find View objects in the layout and define the content for the +ImageView and TextView elements. Then instantiate the AlertDialog.Builder and set the +inflated layout for the dialog with {@link android.app.AlertDialog.Builder#setView(View)}.
+ +Here's an example, creating a custom layout in an AlertDialog:
+ +
+AlertDialog.Builder builder;
+AlertDialog alertDialog;
+
+Context mContext = getApplicationContext();
+LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER);
+View layout = inflater.inflate(R.layout.custom_dialog,
+ (ViewGroup) findViewById(R.id.layout_root));
+
+TextView text = (TextView) layout.findViewById(R.id.text);
+text.setText("Hello, this is a custom dialog!");
+ImageView image = (ImageView) layout.findViewById(R.id.image);
+image.setImageResource(R.drawable.android);
+
+builder = new AlertDialog.Builder(mContext);
+builder.setView(layout);
+alertDialog = builder.create();
+
+
+Using an AlertDialog for your custom layout lets you +take advantage of built-in AlertDialog features like managed buttons, +selectable lists, a title, an icon and so on.
+ +For more information, refer to the reference documentation for the +{@link android.app.Dialog} and {@link android.app.AlertDialog.Builder} +classes.
+ + + diff --git a/docs/html/images/dialog_buttons.png b/docs/html/images/dialog_buttons.png new file mode 100755 index 0000000000000000000000000000000000000000..81aaec4a6ce5a1be77f29a10d09eacea938b1fde GIT binary patch literal 3701 zcmV-*4vO)KP)7dOkws2s6o)OTXqxl}gJOK!R5Xs~@~@jTA_uun z#!gqm9nCLNI*czkl#b`cmDhowqJy1gb~dy}AKKX1xvi0o>qVm1o{ylS{Ee1ww2wZr z<5`4CL?gHbfh1{9Hkj_Py%AO_8t034uLr?U5HxKBLB{>^gEkP11x3gIBFdY9;A(;H zpA)2vF2bMq>wg7eTvHm1KS{s(704NYQ_&3|1`q>?0mJ}e0C_V}zMq-MA(=Je9E82D zj9Ob&TSndJ*@$D1i5B~QO7^bo|FD9s8!Jl_8C#Mf}lc^ z@>`@=b2@ISSCA?3n*otXW^)n~6FCDuWFokEG+8T%nA*rrxb|vJ<@yE5Mtp;qLw3Ht z9HB8EoPmcCNlitaGlSxZrFlEl9_)TsL zJ~2nG1tiHE0P6=Gpit(V&KdxW>Hz0c%DH;=y;M4lMw`)Pp;nwRjph?8EzkzS4`F0h zgn$bbE}&7e5S0Dg2zssbStFO~YO5Esi`kr|Ym<|c*S;HGS?p$(@K>jaT0qiH(v^n* zxS1 PGA1MO?0kE4?FX^}J z=>YLmc+5+$oqgy|#6kwChZlHrsmtojnco+AcCR~0rD$tfVrSrXc|YiVV6IAr E?PlMZUC^e+!!1%vEDO*1UM(X-w##p&?iWc zTb1$%FNL>&TiIL5<=XQGwpu+|<)h90W;-rzBDIcc0s zvOPMSGmTdeG~{lcf4`c_nIXp|h=S5-ZFF29{#hE&KPk+x?J_3g^n64?;aS)&J0)g4 zKqCvYQfOq{p6WKvx3OH3weGI9!_tTDeJyxid{BJi>OL@KN~PJHAUV#LgIW~CrY1#; zVS&y7VgNCK7(m7$$akPwt+P;VP<2d|u-L`(=g&WdnmTo=lUlA&G#ahLY*fa-M`O8| z!9207HKoAvuwr59Sooyc942NOX5u-uwZz{5IsY}L^B15fP);3CY7^OP_FjK~e|LBH z1q&8*+uPfpxpL(SkH_orgd$-|vHZuCqRIiwst4u?bG|YO76D6w<-t<@Vd)xNXpk#r z8fM~Cm9<|p4SmD_VgNCK7(fgl|Ia`gA6d*Tyy3hxtC);ykOIfQ9NwQCK6s~UpDi25 zAdK3u>*rN_O*ccMIJgDrJru$iOL*KcO2jEh8`a48r6lo-bT@p0WR-?vA<*(>kFzb< z&ed4wpf>=C+mwI6p=BI#OfFf}(%P;VvVY#S{Cht|dpod=FVYH9ccMD~z^;s^;|L@M z%?9(EnIvD%a*ppxO7r~Ii)lNwf<%=shFfwYxZp9d8#;=*GaahqS0^<=XWr3h-0z`d zj@FH0&rjyf;bwMWHw oCtalNiq-jJqu12;h5jPU0{y4NbnFUZSrR>?68M}B z*^+ZDP`4oMJ59_ePL!2PGBL%)&?pq2*j;^EKrC4OpwYkQ3=`}V*cuaC@(RJH$9%!G zqh|8iKLYR!wz(4$-GZE>ve ZVinis zHFH@TK Tw+eIPITik9u6jB+7r{wb+44%({{ta`>a6F_>^(Y z797cd$;Y{|0r&oN7aXlPac_OPE2wq^;PVRI)(F$qYhy33h!nom#lHEi+=cFRuXOpS~ zJG5SBFT4LPoY3TL1xNk_Qxxo0Ee|3nV==+R^MG8Pt$UEO_D`&Kud?I~*bj718W@=3 zNs3`raO$ zlnW9H&0|*EMxGQ#-Wj{`0cRlc=F0G`_gKPcrE>Vogb9O1^{qHPv645_K3F}sHfqzM z!=_oB; {fB&;^KT$iv7sAUPY0&o}CA$js SLH^C(IhV?%vbW1IvS@PU3R8(1u=U3$)0Xrn#v=W39(;)X2maB4Z-H ztR}V2sdZMPZ=mYlj ?0mK0Ereaole%5bK z!8?d+)^zG&DwSHhrW?;7@|eFwWq h ZyQ*bgI5UG=cdXizO<>*{K5aCu;*iS=( %+GXpW4pdVU_KK3cw6Ll?iffL1j+Y` zKlPuviFyKI7M3UX4%i326qx^qiYHnF^RZ_>fNP;@kPO(ga l!E%cA?9RbN4l_fRUa-V zjRm9{zSS En8oe{ec~h1M}yw1D9s6**|ODY7Vym*Ma##bIiEBo*sLfd1O346;S0y+ll|v z+^#Sz&>27sAO;W!!oexWS=Ng;RAR5%R8Ge!$dZ%MV<18dM05e4ASJLuM&II!y;pZw znRADRI|` NHvRwr002ovPDHLkV1m=0@>2i+ literal 0 HcmV?d00001