[FIX][CM11][XPOSED] Fix for Google Camera error on CM11 - Galaxy S III General

This Xposed module I made is a workaraound for the "Cannot connect to camera" problem on i9300 CM11 (Don't know if other devices has the same problem. However, the module may work on every device with Google Camera, because of the way it is implemented). I used the "Restart Camera" apk by temasek for some time, but I shortly got tired of making two or three taps every time I had to take a picture, so I kind of "reverse engineered" the temasek's apk and found out that it just kills the MediaServer process. Then, I build an Xposed module to do this automatically every time the user closes Google Camera app. I wrote that in few minutes so I haven't done a lot of testing, but it seem to work fine on my device and I think it can be shared with other users so everybody can get rid of this bug.
INSTRUCTIONS:
Code:
1. Install Xposed Framework (if you don't have it already)
2. Install the APK
3. Enable the module and reboot the device
4. Start Google Camera, wait until it loads the preview, then press the "Back" key to exit. When prompted, grant Google Camera root access for every future requests
5. Enjoy
SOURCE CODE:
Code:
package jager.cmcamerafix;
import java.io.DataOutputStream;
import java.io.IOException;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class CameraFix implements IXposedHookLoadPackage {
XC_MethodHook mMethodHook = new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
try {
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
outputStream.writeBytes("killall mediaserver\n");
outputStream.flush();
outputStream.writeBytes("exit\n");
outputStream.flush();
su.waitFor();
} catch (IOException e) {
throw new Exception(e);
}
}
};
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.google.android.GoogleCamera"))
return;
findAndHookMethod("com.android.camera.CameraActivity", lpparam.classLoader, "onStopTasks", mMethodHook);
}
}
CREDITS:
Code:
- temasek for "Restart Camera" apk
- robv89 for Xposed Framework
@Moderators: I wrote here because I haven't got permissions to write in the Dev section. Sorry.

lollipop compability
This module that can be compatible with android 5.0?

Lollipop
Working great on Lollipop 5.1.1! HUGE THANK YOU

Edited Version for cm13
thanks jagger for your module
i tested it on cm13 rom but it does not work, so i edit it and makes some updates to get it work with cm13 stock camera ( cyanogenmod snap camera )
new version in attachments

Related

[app][root]SecHoleUtils.apk 1.1 Control GPS and PIN from your app. KitKat ready.

Google has always limited the access to several features like GPS on/off management, PIN control and more to third party applications. Sometimes the developers have taken advantage of certain security bugs to circonvent those limitations, but Google has fixed those bugs on the latest OS version.
There are certain functions that in my opinion should be allowed because the security risk is minimun, like GPS control and SIM PIN entering , so I've wr1tten a small app to open this possibility. It does nothing by itself and is not normally loaded but registers for specific intents and when received does those forbidden functions.
Any thir party application can take advantage of it, no need to ask for permisions. Simply broadcast and intent and voila!
Sample usage code:
Code:
public static final String TOOGLE_GPS = "com.beemer.secholeutils.TOOGLE_GPS";
public static final String ENTER_PIN = "com.beemer.secholeutils.ENTER_PIN";
public static final String EXTRA_PIN = "com.beemer.secholeutils.EXTRA_PIN";
public void toogleGPS() {
Intent intent = new Intent(TOOGLE_GPS);
sendBroadcast(intent);
}
public void enterPIN(String PIN) {
Intent intent = new Intent(ENTER_PIN);
intent.putExtra(EXTRA_PIN, PIN);
sendBroadcast(intent);
}
Disclaimer
I'm nor responsible of what happens to your device if you install this apk or while you install it.
Installing this app could allow any third party app to use it to turn on/off the GPS or enter your SIM PIN (if known) even try an brute force atack without asking for permission.
The app must be installed as a system app. You can do it manually but from kitkat on it has became somewhat difficult. I recomend installing busybox and systemappmover from Play store:
https://play.google.com/store/apps/details?id=stericson.busybox
https://play.google.com/store/apps/details?id=de.j4velin.systemappmover
Install secHoleUtils.apk as a normal app and use SystemAppMover to make it a system app.
DEBUG
In order to debug your app, SecHoleUtils will log the calls and errors if they happens:
Code:
pre-KitKat
Log.i("SecHoleUtils", "Received " + TOOGLE_GPS + " intent");
Kitkat:
Log.d("SecHoleUtils", "ToogleGPS. Current mode: " + currentMode + " newMode: " + newMode);
Log.e("SecHoleUtils", "Error toogling GPS");
Log.i("SecHoleUtils", "Received " + ENTER_PIN + " intent");
Log.e("SecHoleUtils", "Error inserting PIN");
Detection of the APK
In order to detect in your app if SecHoleUtils is installed and you can use it, there is a sample code:
Code:
//Test if SecHoleUtils.apk is installed
boolean bSecHoleUtils = false;
try {
getPackageManager().getPackageInfo("com.beemer.secholeutils",PackageManager.GET_META_DATA);
bSecHoleUtils = true;
}
catch (NameNotFoundException e1){}//Not installed. No need to do anything.
If I see interest in the app, I'll add more APIs to it.

2G/3G Preferred Network Mode with root?

I'm trying to access the hidden API for Phone.class to switch the preferred network mode via reflection.
I know this is not safe for porting to other android versions/roms and requires a system app to hold permission WRITE_SECURE_SETTINGS.
I Already managed to switch data via reflection and toggle gps via Settings.Secure.putString() by moving my app to system partition, so i think this should work too.
Does anyone have experience with reflection and/or root and is willing to help?
Of course I will share all my code/findings here.
Thanks in advance!
Links:
http://stackoverflow.com/questions/8607263/android-4-0-4g-toggle
http://stackoverflow.com/questions/5436251/how-to-access-setpreferrednetworktype-in-android-source
You can achieve this with a simple sqlite3 query instead of bothering with java reflection
Here's how :
In a terminal :
To enable 2G only
Code:
su
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
insert into global values(null, 'preferred_network_mode', 1);
.exit
To enable 2G & 3G :
Code:
su
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
insert into global values(null, 'preferred_network_mode', 0);
.exit
In java :
Example to enable 2G only (just replace the 1 with a 0 in the insert into to enable 2G & 3G)
Code:
try {
Process process = null;
process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(
process.getOutputStream());
os.writeBytes("sqlite3 /data/data/com.android.providers.settings/databases/settings.db" + "\n");
os.writeBytes("insert into global values(null, 'preferred_network_mode', 1);" + "\n");
os.writeBytes(".exit" + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
It might require a reboot to be active though, not sure
If it doesn't work on your rom (tested on cm10.1), it might be a different row name, try investigating your settings.db like this :
Code:
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
.tables [COLOR="Green"]// returns all the tables[/COLOR]
select * from [I]tablename[/I]; [COLOR="green"]// in cm10.1 it's in [I]global[/I] but otherwise look in [I]secure[/I] and/or [I]system[/I]
// this command returns all the rows from the selected table, the names are usually explicit, so you should find the setting you're looking for[/COLOR]
Then, when you found it :
Code:
insert into [I]tablename[/I] values(null, [I]'row name'[/I], value);
Thanks, this is very helpful!
I think you are right, one will need to tell the system to update the settings or send a broadcast that this setting has changed (like for airplane mode).
I will look at the CM sources to find out what i can do.
superkoal said:
Thanks, this is very helpful!
I think you are right, one will need to tell the system to update the settings or send a broadcast that this setting has changed (like for airplane mode).
I will look at the CM sources to find out what i can do.
Click to expand...
Click to collapse
Glad it helped.
If you manage to find a way to make the settings read the db without a reboot, please share your findings, would be very useful.
Androguide.fr said:
Glad it helped.
If you manage to find a way to make the settings read the db without a reboot, please share your findings, would be very useful.
Click to expand...
Click to collapse
Of course i will!
Buddy... you can toggle network mode with intent, no root needed, nor permissions!!
HereĀ“s entire sample:
Code:
package com.serajr.togglenetworkmode;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bnt = (Button) findViewById(R.id.button1);
bnt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// toggle
toggleNetworkMode();
}
});
}
private void toggleNetworkMode() {
int mode = getCurrentNetworkMode() + 1;
if (mode > 2) {
mode = 0;
}
// 0 = 3G_ONLY
// 1 = 3GSM_ONLY
// 2 = 3G_PREFERRED
// change mode
Intent intent = new Intent("com.android.phone.CHANGE_NETWORK_MODE");
intent.putExtra("com.android.phone.NEW_NETWORK_MODE", mode);
sendBroadcast(intent);
}
private int getCurrentNetworkMode() {
try {
int current = Secure.getInt(getContentResolver(), "preferred_network_mode");
return current;
} catch (SettingNotFoundException ex) {
return 0;
}
}
}
Try it and tell me later!!!
Thanks, but this will only work if your phone.apk has an exported receiver for this intent.
This is only the case if you or your rom dev modded it to be so.
Some custom ROMs also have this kind of "mod/bug" in the power widget, allowing you to toggle gps.
I tried it with slim bean 4.2 build 3 on i9000 and as expected it didn't work (and so will most likely in CM10.1 too).
Just too good to be true!
If youre following the root method Use RootTools for that
sak-venom1997 said:
If youre following the root method Use RootTools for that
Click to expand...
Click to collapse
Thanks, I already do.
Really helpful library!
And yes, I will do it by sql injection to settings.db
I only need to figure out what broadcasts have to be sent / methods called and if this is possible.
Argh I am kinda lost in CM sources.
Can anyone point me to the place where this is handled?
I managed to toggle flight mode by using this in a SU shell:
Code:
if(settingenabled)
{
executeCommand("settings put global airplane_mode_on 1");
executeCommand("am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true");
}
else
{
executeCommand("settings put global airplane_mode_on 0");
executeCommand("am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false");
}
Interstingly enough it didn't work if i manually injected the value and then sent the broadcast.
I have no idea why.
So atm I'm trying to do the same thing for preferred_network_mode. I can write the value to settings.db, but I just don't know what i have to do to make the system apply the setting yet.
EDIT: shell binary "settings" only works in android 4.2 (and probably upwards)
So i finally found it in CM Sources.
Seems like we need to get the currently running Instance of the Phone class to notify it about the change.
Also seems like we are back to reflection, as this is an internal system class.
I also killed com.android.phone process after updating the setting, but that didn't change anything.
EDIT:
1st step towards reflection:
I figured out that i need a jar file from the cm build to use system classes via reflection.
Does anyone have more information about this?
superkoal said:
So i finally found it in CM Sources.
Seems like we need to get the currently running Instance of the Phone class to notify it about the change.
Also seems like we are back to reflection, as this is an internal system class.
I also killed com.android.phone process after updating the setting, but that didn't change anything.
EDIT:
1st step towards reflection:
I figured out that i need a jar file from the cm build to use system classes via reflection.
Does anyone have more information about this?
Click to expand...
Click to collapse
Just a far fetched guess, but maybe try to add /system/framework/framework.jar from your rom to your app's build path
Is a reboot that unacceptable in your case ?
Maybe it's just the challenge, but i wanna change it like every other setting
A reboot is very far from what i call comfortable
superkoal said:
Maybe it's just the challenge, but i wanna change it like every other setting
A reboot is very far from what i call comfortable
Click to expand...
Click to collapse
Yeah, I get what you mean^^^
Here's a good (but old, 2009^^) official Android tutorial from the Android devs on reflection if it can help you : http://android-developers.blogspot.fr/2009/04/backward-compatibility-for-android.html
So i got some news
1. This setting is heavily protected by android system and can only be modified by the phone process itself
2. Some roms have a modified phone apk listening to a broadcast, enabling 3rd party apps to toggle
http://forum.xda-developers.com/showthread.php?t=1731187
3. His Majesty Chainfire started an app project which could amongst other features also toggle 2g/3g, but he gave up development. Regarding 2g/3g he implemented several methods, one of them being RIL injection, which he described as a really hard hack and highly experimental.
http://forum.xda-developers.com/showthread.php?t=807989
Seems this task is not that easy
But i found out that tasker can toggle 2g/3g on my phone (running slim bean 4.2.2), this is when i found out about the modified phone.apk from 2). So I'mcomfortable that it's working on my phone and i can at least develop an app for myself
Sent from my GT-I9000 using xda app-developers app

[Q] Widget pick code not working only on LG G2

Sorry if I'm at wrong place to ask, I couldn't find other place I can ask this question.
There's a simple code that brings up widget list to let user select widget, and code looks like below.
This works fine on other devices, but causes error only with LG G2 with KitKat (Message "Unfortunately, xxxx has stopped").
It works fine with android SDK KitKat emulator and Nexus 7 with KitKat, so I belive it's not KitKat issue, but something with KitKat rom for LG G2.
This was reported by user of my app, and since I don't have actual device, I can't get stack trace, etc.
Any idea why this simple code does not work on LG G2 / KitKat?
Code:
public class samplecode extends Activity {
AppWidgetHost appWidgetHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
appWidgetHost = new AppWidgetHost(this, 3322);
}
public void onClickAddwidget(View view){
int appWidgetId = appWidgetHost.allocateAppWidgetId();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(intent, REQUEST_CODE_ADD_APPWIDGET);
}

[Source-Code] [LGSignBoard] 2nd screen Controller, Decompiled to useable source

LGSignBoard: As most of you probably already know the 2nd screen is controlled by This app called LGSignBoard..
There are 4 apps.. I took the time to decompile everything down to usable source if you know what your doing.
I am posting this up, In hopes that someone can build a fully working app that would control your 2nd screen within CM......................
For the most part, all sources seem to be 100% there.. Only a few areas known for INTERNAL Error, No source.. but that was clock setting......
Download The Following Source Code:
LGSignBoard
LGSignBoardInitialGuide
LGSignBoardProvider
LGSignBoardSettings
Download The Following Source Code RES FILES:
LGSignBoardInitialGuide2_apk
LGSignBoardProvider2_apk
LGSignBoardSettings2_apk
LGSignBoard2_apk
Not sure if this would be of any use to anyone.. But its a start.........
Exampled of code:
Code:
package com.lge.signboard.baseservice.layer;
import com.lge.signboard.baseservice.layer.blackout.SBBlackOutLayer;
import com.lge.signboard.baseservice.layer.content.SBContentLayer;
import com.lge.signboard.baseservice.layercontroller.ISBLayer;
import com.lge.signboard.baseservice.layercontroller.ISBLayerController;
import com.lge.signboard.common.ISBContext;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SBLayerContainer
{
private static List<ISBLayer> mLayers;
public static void loadLayers(ISBContext paramISBContext, ISBLayerController paramISBLayerController)
{
if (mLayers == null)
{
mLayers = new ArrayList();
mLayers.add(new SBBlackOutLayer(paramISBContext));
mLayers.add(new SBContentLayer(paramISBContext));
paramISBContext = mLayers.iterator();
while (paramISBContext.hasNext()) {
paramISBLayerController.addLayer((ISBLayer)paramISBContext.next());
}
}
}
public static void unloadLayers(ISBContext paramISBContext, ISBLayerController paramISBLayerController)
{
if (mLayers != null)
{
if (paramISBLayerController != null)
{
paramISBContext = mLayers.iterator();
while (paramISBContext.hasNext()) {
paramISBLayerController.removeLayer((ISBLayer)paramISBContext.next());
}
}
mLayers.clear();
mLayers = null;
}
}
}
Code:
package com.lge.signboard.application;
import android.app.ActivityManagerNative;
import android.app.Application;
import android.app.IActivityManager;
import android.app.IUserSwitchObserver;
import android.app.IUserSwitchObserver.Stub;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.support.v4.content.LocalBroadcastManager;
import com.lge.app.MiniActivity;
import com.lge.signboard.DriveModeObserver;
import com.lge.signboard.NotificationHistoryReceiver;
import com.lge.signboard.PackageResourceAccessor;
import com.lge.signboard.SBDPMListener;
import com.lge.signboard.SBPowerSaverListener;
import com.lge.signboard.SignBoardSupport;
import com.lge.signboard.SmartCoverHandler;
import com.lge.signboard.TimeChangeAlarm;
import com.lge.signboard.TimeTickManager;
import com.lge.signboard.aod.AodService;
import com.lge.signboard.baseservice.SBBaseService;
import com.lge.signboard.common.ISBContext;
import com.lge.signboard.common.ISBManagerContainer;
import com.lge.signboard.common.SBContext;
import com.lge.signboard.eventlistener.EventListenerService;
import com.lge.signboard.lib.util.SBLog;
import com.lge.signboard.los.LOS_SharedPreferenceConverter;
import com.lge.signboard.manager.SBManagerContainer;
public class SBApplication
extends Application
{
private ISBManagerContainer mManager;
private IUserSwitchObserver mUserSwitchObserver;
private IUserSwitchObserver getUserSwitchObserver()
{
if (this.mUserSwitchObserver == null) {
this.mUserSwitchObserver = new IUserSwitchObserver.Stub()
{
public void onForegroundProfileSwitch(int paramAnonymousInt)
throws RemoteException
{}
public void onUserSwitchComplete(int paramAnonymousInt)
throws RemoteException
{}
public void onUserSwitching(int paramAnonymousInt, IRemoteCallback paramAnonymousIRemoteCallback)
{
SBApplication.this.startServices();
}
};
}
return this.mUserSwitchObserver;
}
private void registerUserSwitchObserver()
{
try
{
int i = ActivityManagerNative.getDefault().getCurrentUser().id;
IUserSwitchObserver localIUserSwitchObserver = getUserSwitchObserver();
if ((i == 0) && (localIUserSwitchObserver != null)) {
ActivityManagerNative.getDefault().registerUserSwitchObserver(localIUserSwitchObserver);
}
return;
}
catch (Exception localException)
{
SBLog.w("Cannot register UserSwitchObserver");
}
}
private void startServices()
{
Context localContext = SBContext.getInstance().get();
localContext.startServiceAsUser(new Intent(localContext, EventListenerService.class), new UserHandle(-2));
if (MiniActivity.isExternal())
{
localContext.startServiceAsUser(new Intent(localContext, SBBaseService.class).setAction("com.lge.signboard.intent.action.ACTION_START_SERVICE"), new UserHandle(-2));
return;
}
localContext.startServiceAsUser(new Intent(localContext, AodService.class), new UserHandle(-2));
}
public Context createPackageContext(String paramString, int paramInt)
throws PackageManager.NameNotFoundException
{
return super.createPackageContext(paramString, 3);
}
public void onCreate()
{
super.onCreate();
Context localContext = getApplicationContext();
SignBoardSupport.start(localContext);
LocalBroadcastManager.getInstance(localContext);
if (LOS_SharedPreferenceConverter.hasSharedPreference(localContext)) {
LOS_SharedPreferenceConverter.convertSharedPreferenceToDatabase(localContext);
}
SBContext.create(localContext);
ISBContext localISBContext = SBContext.getInstance();
this.mManager = new SBManagerContainer(localISBContext);
localISBContext.setManagerContainer(this.mManager);
this.mManager.start();
SBPowerSaverListener.getInstance(localContext).start();
SBDPMListener.getInstance(localContext).start();
registerUserSwitchObserver();
TimeChangeAlarm.getInstance(localContext);
NotificationHistoryReceiver.start(localContext);
SmartCoverHandler.start(localContext);
DriveModeObserver.start(localContext);
PackageResourceAccessor.start(localContext);
TimeTickManager.start(localContext);
startServices();
}
public void onTerminate()
{
SBContext.getInstance().setManagerContainer(null);
SBContext.destroy();
this.mManager.stop();
this.mManager = null;
SBPowerSaverListener.getInstance(getApplicationContext()).stop();
SBDPMListener.getInstance(getApplicationContext()).stop();
NotificationHistoryReceiver.stop();
SmartCoverHandler.stop();
DriveModeObserver.stop();
PackageResourceAccessor.stop();
TimeTickManager.stop();
super.onTerminate();
}
}
Uploaded The RES Files also now, These files have the FULL Res, as in lib and anything else missing....................
Now with all files, you can build an Android Studio Project..
Pointless
I got some ideas on how to use the LGSignBoard with CM based roms, Or shall I say Custom Roms........
We just need to make sure we hijack the lge-res-apk............
With that.. we can install the apks and they shall work.. But we will also need to add an option to cm settings config that will
allow access to such app to make changes................
The lge-res.apk is in system/framework
we might also need to make sure we hijack the sdk libs as well......................
Other then that.. I think we are good to go..............................
That should give us working 2nd screen control on a Custom Rom.......................
I looked at the source code enough and messed with some other things, that gave me the idea....... See we dont need the source code realy.......
I decompiled it only to see what it was doing and how it was making its calls.......
Now that I know all that.. we can just use the apk it self........ but with the apk you need resource, which is called lge-res-apk, This is LG's framework..........
without it. you cant run them apps.. you will get an error...............
Well thats my idea...... Call me crazy but I think it will work..................
Just saw this. Wow I suggest this very idea for use with CM 12 and get laughed out of the room.
I guess it was my delivery.....
-sent from this device using this app.
It would be awesome if someone could mod this so the notifications, battery status, signal status, ect..... Were all in the second screen.
Sent from my LG-H901 using XDA-Developers mobile app
posted this in cm forums
Still open huh? Thought you were locking everything down?
markbencze said:
Still open huh? Thought you were locking everything down?
Click to expand...
Click to collapse
This thread seems to be self-entitled prick ridden so far. Maybe because it isn't something you can simply flash in recovery? [emoji13]
Any Further Development?
I know it's been a while, but has there been any recent development on creating this fix? If I knew how to code and stuff I'd dive in myself but I can't. If this is figured out it'll bring a well deserved life back to this phone as we all know. Any lessons? lol
Good Idea
I see what you are trying to accomplish here. I too am trying to get 2nd screen working on custom roms. I've been hacking at this for a couple days now trying to get my ROM to the v20. Now that it boots, it's time to start fixing and adding things. With your post, I might be able to track back and add the code to the ROM, and get 2nd screen working... Thanks...
Unfortunately, the files are no longer available for download. Think you could upload them again?
has this been abandoned?

Beginner Developer Here Needing Help

I'm making a project in Android Studio that requires the user to give permissions. The only code that I've found online and in YouTube tutorials is the following code:
public void onClick(View v) {
Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.setData(Uri.parse("package:" + getPackageName()));
i.addFlags(Intent.FLaG_ACTIVITY_NEW_TASK);
startActivity(i);
}
It works however, I would like a direct code that will open permissions directly for my app. Not just the details. I know it's one click over but I would still like a direct code that will popup that permissions area at users request. I appreciate the help that I can get with this.

Categories

Resources