As a child, I was enthralled by the vivid illustrations and mysterious symbols within the pages of the Book of Abraham. I remember being captivated by the intricate facsimiles before I could even read the words surrounding them. These images, with their ancient allure, planted the seeds of a fascination that would grow and evolve throughout my life. They set the stage for a profound journey of faith, doubt, and discovery that has shaped my worldview in ways I could never have anticipated.
Today, I aim to share my personal journey with the Book of Abraham, a journey that has taken me from unquestioning faith to critical inquiry and beyond. My hope is to provide a balanced and well-researched perspective that can help others understand the complexities and criticisms surrounding this controversial text. By shedding light on my own experiences and the scholarly debates, I seek to enable informed decision-making about religious beliefs, even if it means confronting uncomfortable truths.
My initial encounter with the Book of Abraham occurred in the halls of my local LDS church. As a young child, I would flip through the pages of the book during sacrament meetings, drawn to the enigmatic facsimiles that seemed to hold ancient secrets. These visual depictions of what I later learned were scenes from Abraham’s life and visions sparked an early fascination. The figures, symbols, and hieroglyphs captured my imagination, setting the foundation for a deep and abiding interest in the text and its origins.
It wasn’t until I was 18, undergoing chemotherapy, that I first read the Book of Abraham in its entirety. At that time, the words provided a familiar comfort, resonating with the tone and style of other LDS scriptures I had grown up with, such as the Bible (KJV), the Book of Mormon, and the Doctrine and Covenants. In the midst of my health struggles, these texts offered a sense of stability and hope. I read them as if they were indisputable facts, a reflection of my religious upbringing and the teachings that shaped my early years.
This initial reading was the beginning of a journey that would see my faith both strengthened and ultimately questioned. The Book of Abraham, with its unique narrative and themes, would play a central role in this complex and evolving process.
During my mission, a two-year period often considered mandatory for young LDS men, my interest in the Book of Abraham deepened significantly. A high-ranking church leader shared his interpretations of facsimile #2 with me, drawing elaborate illustrations that represented his understanding of the cosmos. I was captivated by his insights and the way he connected these ancient symbols to profound spiritual truths. Inspired, I added similar drawings to my own copy of the Book of Abraham, feeling that I was gaining a special, almost esoteric knowledge that enhanced my spiritual journey.
As I delved deeper into the text, I found myself increasingly fascinated by its narrative and themes. The Book of Abraham seemed to offer a unique perspective on the cosmos, creation, and the nature of God, which resonated deeply with my own spiritual inquiries. I often shared these insights in my teachings, both during my mission and later as a Sunday School and Elders Quorum instructor. Certain passages became ingrained in my memory, and I took great pride in sharing what I believed to be profound truths with fellow members of the church.
Upon returning home from my mission, I had access to a wealth of scholarly resources that further fueled my study. Works by LDS scholars like Hugh Nibley provided deeper insights into the historical and cultural context of the Book of Abraham. My fascination grew even stronger during a trip to Egypt, where I immersed myself in the study of Egyptology and ancient symbolism. At that time, I was fully convinced that I was a member of the one true church, possessing unique and divinely revealed knowledge about the ancient world.
However, my faith began to waver when I came across the CES Letter, a document that compiled various criticisms of LDS truth claims, including those related to the Book of Abraham. This letter introduced me to a range of critical perspectives that challenged my previous understanding. Initially, I leaned heavily on apologetic responses to counter these doubts. But the seeds of uncertainty had been planted, and they would continue to grow as I delved deeper into my studies.
A pivotal moment in my journey came in 2018 when I discovered a critical website that highlighted the chiseled head of Anubis in facsimile #3. Joseph Smith had translated the Egyptian god Anubis as a slave and chiseled out his head to make him look human. This discovery led me to re-examine the apologetic arguments I had relied on. The more I investigated, the more it became clear that these defenses were fundamentally flawed. The evidence overwhelmingly suggested that Joseph Smith’s translation did not align with the actual content of the papyri.
In my quest for understanding, I engaged with scholars like Dan Vogel and Brian Hauglid. Vogel’s meticulous research and Hauglid’s shift from an apologetic stance to a more critical perspective provided the intellectual support I needed to navigate my doubts. Additionally, the work of Egyptologist Robert K. Ritner, a non-LDS scholar, offered critical insights into the Book of Abraham’s translation issues. Conversely, interactions with apologists like Jeff Lindsey, and observing the work of Kerry Muhlestein and John Gee, left me disillusioned with their attempts to defend the indefensible aspects of the Book of Abraham.
Some LDS scholars propose the “catalyst theory,” suggesting that the papyri served merely as a trigger for divine revelation rather than a source text for a literal translation. According to this theory, Joseph Smith received the text of the Book of Abraham through inspiration, and the papyri were simply a means to spark this revelatory process.
However, this theory does not hold up under scrutiny for several reasons:
The Book of Abraham ultimately served as a catalyst for my transition of faith. It expanded my worldview, helping me navigate through a long and challenging battle with cognitive dissonance. Although I lost certain beliefs, I gained a deeper understanding of historical and scholarly contexts.
Creating content to help others understand the criticisms of the LDS church’s truth claims is not just a passion but a responsibility. By sharing my journey, I hope to provide support and insight for those grappling with similar doubts. It’s crucial to approach these topics with a balance of empathy and rigorous scholarship, fostering an environment where individuals feel empowered to explore and question their faith.
I encourage readers to engage with scholarly research and critical perspectives. Explore your beliefs with an open mind and seek out balanced, well-informed resources. Understanding the complexities of religious texts like the Book of Abraham can lead to a more nuanced and informed faith journey. If your journey leads you away from the LDS Church, know that there are many paths to a fulfilling and meaningful spiritual life. Seek out communities, philosophies, and practices that resonate with your newfound understanding and provide support and growth in your personal faith journey.
LDS truth claims.
By understanding these perspectives and engaging in informed dialogue, we can navigate our spiritual journeys with greater clarity and confidence.
]]>When I started heavy chemotherapy at the age of 17-years old followed by a complex Retroperitoneal Lymph Node Dissection (RPLND) that left me with an 18 ½ inched scar, rib damage, and over 100 staples, I was completely unprepared for the physical and mental damage it caused me. One person helped me through it all: my nurse, Leigh Maple. Leigh wasn’t just a nurse; she was akin to a psychotherapist too. Nurse Leigh would calm my high anxiety during chemotherapy treatments. She thought of me outside of the weeks where I would spend ~8 hours being pumped with chemicals designed to destroy my cells. Nurse Leigh presented me with a cake in the chemo room on my 18th birthday. When I “graduated” from chemotherapy treatments I missed nurse Leigh and the emotional support she gave me as I anxiously awaited the gruesome surgery to follow. I spent Thanksgiving and Christmas in the hospital that year recovering from my surgery.
I kept in contact with my nurse, and she attended my farewell speech when I left on a mandatory 2-year mission, not long after being in remission, for The Church of Jesus Christ of Latter-day Saints (also known as the Mormon church), my wedding, and a baby shower for my oldest daughter. In October I received a message that my nurse retired and was interviewed for an exhibit to be displayed by the Richard Nixon Foundation to commemorate the 50th anniversary of the beginning of the War on Cancer. My nurse was featured in the exhibit along with my story about how I was told that having children would not be possible. The exhibit features a picture of my wife and our two beautiful daughters. The Universe only knows how grateful I am for the science of In vitro fertilization that made having children possible!
While amazed at the impact of bipartisan legislation, miraculous science, generous philanthropists, skilled doctors, and superhero nurses, I have written this open letter because I am fearful—fearful that history will repeat itself. The world is ill and in commotion regarding healthcare due to COVID-19 and its variants. While, as a nation, we accomplished so much with the investment signed into law by Richard Nixon, I believe we fell short in addressing survivorship. We fell short to use our vast wealth and resources in addressing mental health for cancer survivors and other minorities. On December 2nd, at the Nixon National Cancer Conference, I asked the brilliant panelists: what has and will be done in the next 50-years in the war on illness.
Peter Pisters, M.D., President of The University of Texas MD Anderson Cancer Center, responded by stating:
[When] all of us went to medical school, mental health and physical health were dichotomized… [and now] mental health issues are being destigmatized… [mental health] is a part of normal life and that’s something that we have to help people understand. It’s especially acute in cancer patients who’ve gone through a life changing, life threatening experience and as we think about really reconfiguring survivorship, uh.. we are doing you a disservice by not focusing on the mental health challenges associated with survivorship. 1
Steven T. Rosen, M.D., Medical Oncologist and Hematologist; Provost and Chief Scientific Officer; Irell and Manella Cancer Center Director’s Distinguished Chair; Morgan & Helen Chu Director’s Chair of the Beckman Research Institute responded to the question by quoting the words at the gate of the City of Hope, which reads:
THERE IS NO PROFIT IN CURING THE BODY IF IN THE PROCESS WE DESTROY THE SOUL 2
It is my humble pleading that at the 100th-year anniversary of the War on Cancer that we can say with confidence—not only to cancer but to all illness—that we did all we could to bring peace to the soul. America, in my opinion, must use the vast resources we have amassed to strengthen trust in democracy, set aside divisive divisions, and come together to bring healing in this time of turmoil. I have ideas on how this can be done and I’m excited to share them with you.
1 “Nixon National Cancer Conference - Panelists and Keynote by Dr. Ned Sharpless.” Panelists: Nobel laureate James P. Allison, Ph.D., Nobel laureate David Baltimore, Ph.D., Nobel laureate Phillip Sharp, Ph.D., Andrew von Eschenbach, M.D., Former National Cancer Institute Director, Former Commissioner of the Food and Drug Administration, Stephan A. Grupp, M.D., Ph.D., Section Chief of the Cellular Therapy and Transplant Section at Children’s Hospital of Philadelphia, Lori J. Pierce, MD, FASTRO, FASCO, Chair of the American Society of Clinical Oncology Board of Directors, Professor and Vice Provost for Academic and Faculty Affairs, University of Michigan, Peter Pisters, M.D., President of The University of Texas MD Anderson Cancer Center, Steven T. Rosen, M.D., Medical Oncologist and Hematologist; Provost and Chief Scientific Officer; Irell and Manella Cancer Center Director’s Distinguished Chair; Morgan & Helen Chu Director’s Chair of the Beckman Research Institute, Ned Sharpless, M.D., – Director of the National Cancer Institute, YouTube, 2 Dec. 2021, https://youtu.be/Ms9WpZEGzzA?t=7450.
2 Ibid., https://youtu.be/Ms9WpZEGzzA?t=7660
Below are links related to the Nixon National Cancer Conference:
getRunningTasks(int) and
getRunningAppProcesses() in Android 5.0. Both of these methods now only return the caller’s
application process.
As an alternative workaround, Android 5.0 introduced UsageStatsManager which provides access to
device usage history and statistics. This API requires the permission android.permission.PACKAGE_USAGE_STATS, which is
a system-level permission and will not be granted to third-party apps. However, declaring the permission implies
intention to use the API and the user of the device can grant permission through the Settings application. Several users
and developers reported that some OEMs have removed this preference from Settings. Therefore, this isn’t very reliable
and useful for developers or users who want to access information on what processes are running on a device.
I think every operating system should allow the user to easily discover what applications are currently running on a
device and provide an API to do so. I was determined to find a way to get a list of running processes on Android 5.0.
First, I ran the ps command in a shell and parsed the output. This worked but it wasn’t efficient. After seeing many
fellow developers post about this issue on StackOverflow, I determined I would develop an open source library to work
around Google’s changes.
In October 2015 I open sourced the AndroidProcesses library. To my surprise, the library started trending on GitHub and was quickly forked by developers in China where it received even more attention.
I recently decompiled the top 150 free apps on Google Play and was surprised by how many apps were using the library. Companies using the library include Cheetah Mobile and Baidu. Apps I found that are currently using the library include ES File Explorer, Clean Master, Security Master, CM Launcher 3D, Virus Cleaner by Hi Security, and Super Cleaner. Combined, these apps have at least 1.2 billion downloads!
I personally don’t like these “task manager” type apps that falsely promise to boost your device’s performance. Apparently, Google is not so fond of these large Chinese firms’ apps either. One may wonder if Google and these large Chinese firms are both collecting app usage statistics to improve ad targeting and Google’s restrictions are mainly aimed at these firms rather than for security reasons.
In Android 7.0 (Nougat) Google significantly restricted access to the file system which makes it impossible to get a
list of running processes using my library. The lead developer of CopperheadOS was kind enough to
outline the changes reducing access to /proc:
The procfs filesystem is now mounted with hidepid=2, eliminating access to the /proc/PID directories of other users. This change was implemented in CopperheadOS and was then adopted upstream based on it. There’s a group for making exceptions but it’s not exposed as a permission. It’s only used to make exceptions for some processes in the base system. It could be exposed as a ‘dangerous’ permission and it’s what I expected Google would end up doing but they decided that users wouldn’t understand the implications of it.
https://android-review.googlesource.com/#/c/181345/
SELinux policies also became much stricter. For apps, there’s no baseline access to /proc at all anymore, although that only applies to files other than the /proc/PID directories. There’s still access to a few files with labels not falling under the general proc policy, but it’s mostly gone. This has been gradual and there are many relevant commits. One of the big ones:
https://android-review.googlesource.com/#/c/105337/
This not only removes a lot of obvious information, but it also closes some more blatant security holes involving side channels allowing things like logging keyboard input:
- https://www.lightbluetouchpaper.org/2016/07/29/yet-another-android-side-channel/
- https://staff.ie.cuhk.edu.hk/~khzhang/my-papers/2016-oakland-interrupt.pdf
SELinux policies have also become a lot stricter in general over time. You can see the rest of that in the platform/system/sepolicy repository. Note that it was at platform/external/sepolicy for a long time but it was recently moved.
See: https://stackoverflow.com/a/38728738/1048340
In Android 7.0+ Google’s pre-installed apps will have access to application process information while excluding that information from third-party apps. According to an Android Platform Security Engineer at Google these changes were made to prevent phishing attacks. The Google engineer cited the following two articles in a comment on Android public issue tracker:
However, Tod Liebeck (Founder of NextApp, Inc. which earned Google’s Top Developer Badge) quickly responded by demonstrating that such an attack was still possible in the latest version of Android. Tod’s reply to the security engineer:
I’m quite frankly stunned by this.
I’m an app developer, not a security researcher. What you’ve cited is certainly a real problem, but I believe you are solving it in the wrong way.
And when I say I’m stunned, I mean I’m so stunned I made a demonstration video of the type of malware attack that you are describing here, and I’m running it on an Android N device:
https://www.youtube.com/watch?v=SkvHA1jBpn8
The changes that have been made to Android N which cripple SystemPanel (and other system utilities, security, and antivirus apps) will do little to stop this kind of attack. Again, the only real beneficiaries will be the malware authors who are better able to hide.
In the video above, the fake malware app–which took about 30 minutes to write, by someone who has never written even “fake” malware before–successfully does exactly what you’re talking about on an Android N device. You’re eliminating one way an app can monitor the operations of others, but there are myriad more. The demo above is triggered by network activity to the target app’s network. An identical attack is possible by monitoring that app’s public directory structure on the filesystem.
The real problem here is that applications are permitted to launch themselves arbitrarily. The fake malware demo above launches from a service. This behavior should ABSOLUTELY NOT BE ALLOWED. I had no idea this was possible until I tried it (given that arbitrarily launching an app to the foreground has never come up…perhaps because the only reasons I can think for doing so are malicious).
It seems Google has no plans on providing access to /proc to third-party apps and has since closed the issue. Accordingly, I plan on deprecating the AndroidProcesses library. Hopefully Google will do what CopperheadOS expected them to do and expose a ‘dangerous’ permission allowing users to grant third-party apps access to running app process info.
]]>This has been covered in detail by John Kozyrakis. To quote from his excellent blog post:
“SafetyNet is a data collection system used by Google to gather security-related information from 1 billion Play-enabled Android devices.
The idea is that Google Play Services, a closed-source package on the device starts an always-running service named snet. This service frequently collects various pieces of data from the device and sends it back to Google.
Google uses this information for multiple purposes, such as ecosystem analysis and threat profiling of devices.”
We can’t decompile snet without first knowing where it resides. A quick search on a rooted device (which is required to decompile snet) shows it’s location:
$ find /data/data -type f -iname *snet*
/data/data/com.google.android.gms/shared_prefs/com.google.android.gms.snet.xml
/data/data/com.google.android.gms/databases/snet_safe_browsing.db
/data/data/com.google.android.gms/databases/snet_safe_browsing.db-journal
/data/data/com.google.android.gms/databases/snet_files_info.db
/data/data/com.google.android.gms/databases/snet_files_info.db-journal
/data/data/com.google.android.gms/snet/download/snet_flags
/data/data/com.google.android.gms/snet/installed/snet.jar
/data/data/com.google.android.gms/snet/dalvik-cache/snet.dex
Without diving deeper, it looks like Google is loading snet as a secondary DEX file. Inside snet.jar we find the classes.dex file that can be decompiled.
Before decompiling Safety Net we need to pull it from the device. Run the following commands in a terminal:
adb shell
su
find /data/data/com.google.android.gms -type f -name snet.jar -exec cp {} /sdcard/snet.jar \;
exit
exit
adb pull /sdcard/snet.jar
unzip -p snet.jar classes.dex > snet.dex
Now you should have a file named snet.dex in your current working directory.
There are several tools that can be used to decompile the DEX. I prefer Enjarify or jadx. Other tools include procyon, fernflower, apk-dexguard, and smali/baksmali. If you have jadx installed, simply run jadx-gui snet.dex. You can then save the sources from the options menu.
You’ll find some interesting things in Google’s Safety Net. I haven’t read the code in depth, but it does seem to have access to running app process info, which was denied to developers in Android 7.0 Nougat. Don’t be evil Google.
If you need to use the Safety Net API in your app then check out my open source library SafetyNetHelper on GitHub.
]]>I’m sure you have heard of Google’s “do a barrel roll” Easter egg, but did you know
that YouTube can do the harlem shake? On a Mac you can watch Star Wars: Episode IV in
ASCII characters by running telnet towel.blinkenlights.nl in Terminal. Doing a search for “snake game” with
Bing brings up the game in your search results. There are hundreds of fun hidden Easter
eggs in popular software.
I’ve hidden some Easter eggs in apps I have developed in the past. My first was in December 2010 when I was working on a project, Droid Overclock, with Xeudoxus (Matthew Oaks started following my Twitter account.
Starting with Android version 2.3 (Gingerbread) Google started adding an Easter egg into each release. You can find the Easter egg by going into Settings, then About phone, and then rapidly tapping on Android version.
I enjoyed the Android 5.0 Easter egg so much that I backported it to Android 4.1, added a few more features, and published it as a game to Google Play. The game still has a couple thousand daily active users.
Adding an Easter egg to your Android app is easy and fun. I created a sample app that shows a random Chuck Norris joke after rapidly tapping on the app version. Feel free to add it to your app and make improvements.
To add the Easter egg in your app, first, you will need to create a layout to display the app version. In the example,
I have chosen to do this in a PreferenceFragment. The user will need to click on the app version 7 times to unlock the
Easter egg:
private static final int MAX_CLICKS_TO_UNLOCK_EGG = 7;
private Preference prefVersion;
private int numTimesVersionClicked;
...
@Override public boolean onPreferenceClick(Preference preference) {
if (preference == prefVersion && ++numTimesVersionClicked == MAX_CLICKS_TO_UNLOCK_EGG) {
numTimesVersionClicked = 0;
// The user unlocked our Easter egg!
new EasterEggTask(getActivity()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
return true;
}
The EasterEggTask class gets a random Chuck Norris joke fact:
/**
* Loads a random Chuck Norris nerdy joke and displays a toast message.
*/
public class EasterEggTask extends AsyncTask<Void, Void, String> {
private static final String JOKE_ENDPOINT = "http://api.icndb.com/jokes/random?limitTo=[nerdy]";
...
@Override protected String doInBackground(Void... params) {
// Request a Chuck Norris joke. See http://www.icndb.com/api/
Request request = new Request.Builder().url(JOKE_ENDPOINT).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return new JSONObject(response.body().string()).getJSONObject("value").getString("joke");
}
} catch (Exception e) {
Log.e(TAG, "Error getting a random nerdy joke", e);
}
return null;
}
@Override protected void onPostExecute(String joke) {
Activity activity = weakActivity.get();
if (activity != null && !activity.isFinishing() && !TextUtils.isEmpty(joke)) {
Toast.makeText(activity.getApplicationContext(), Html.fromHtml(joke), Toast.LENGTH_LONG).show();
}
}
}
That was easy and fun. Now you have a simple Easter egg that displays a random Chuck Norris joke. You can download the project from my GitHub. Also, check out these other Android Easter eggs. Happy coding.
]]>The week after I finished my sophomore year of high school I broke my collar bone. About four months later I broke my collar bone again. I had a hernia surgery before breaking my collar bone for yet a third time in less than ten months. This was only the beginning of my misfortune of health that would follow me for the next couple years.
During my senior year of high school I started to get intense pain in my abdomen and lower back. The pain was so severe that it kept me up most nights. Often, in the middle of the night, I would get very hot water to pour on my back and abdomen to relieve the pain.
I went to the ER several times. Each time they would dismiss me without performing significant tests. The nurses, doctors, my parents and friends didn’t take my discomfort seriously. I looked like a healthy 17-year-old; there was no reason to believe that anything was seriously wrong. However, I knew something had to be wrong. There were times where I could barely walk from the indescribable pain I was in.
A week after graduating high school in 2003 my family went on vacation to Waikiki, Hawaii. I spent most of the trip in extreme pain. The day we planned to fly home a miracle happened. Everyone was boarded on the flight to LAX. The flight safety instructions were already given and we were about to depart. I was seated next to my mom. Randomly, I whispered to my mom that I could not make the flight home that day. Concerned and with no other options she tried to calm me down and explain that there was no way we could get off the flight. A few minutes later the captain addressed everyone, explaining that the plane had unexpected engine problems.
As soon as I got off the plane an incredible amount of pain overcame me. I rushed to the nearest bathroom and vomited uncontrollably. I was taken in an ambulance to the Queen’s Hospital in Honolulu. Unfortunately, there was high surf that day which sent many people to the hospital. I spent a grueling six hours waiting for any treatment. Finally, I was given pain medication and a CT scan with contrast dye. I was told that the results of the scan showed a mass in the retroperitoneal area, and also a possible tumor or blood clot in my left renal vein to the inferior vena cava. I was to go to the hospital as soon as I arrived home in California.
I went to St. Jude Medical Center in Fullerton when I arrived home on June 22nd, 2003. I was anxious and still in serious pain. I was given morphine, dilaudid, and ativan for my pain and anxiety. I was so drugged up that I can’t remember much of my week-long stay at the hospital.
The doctors had a difficult time with the diagnoses. I was told that I had blood clots, and I was started on a blood thinner (Coumadin) immediately. The next day I was diagnosed with stage III non-seminoma testicular cancer which had spread to my lungs.
Normally, a radical inguinal orchiectomy (a surgery to remove a testicle) would be performed first. However, because I was on blood thinner any surgery would have to wait. I was to start chemotherapy immediately. My oncologist, Dr. William Lawler, commenced treatment with cisplatin, etoposide and bleomycin for four cycles which started in the end of June and ended in September of the same year.
Chemotherapy treatment varies significantly from case to case. For me, each cycle of chemotherapy lasted three weeks. For the first week I would go into the cancer center from Monday to Friday and get pumped with chemo from 7 AM to 4 PM. I would then wait two weeks before the next cycle began. I was ignorantly jealous as I spoke with other cancer patients who had far less side effects and who only spent a few hours getting treatments. However, I was fortunate that my cancer had a high cure rate.
The two weeks after a cycle were the worst. I felt as sick as I had ever felt. I could barely eat anything without vomiting. I went to bed with a bucket each night and when I woke up in the morning I would stay perfectly still for about 30 minutes to avoid throwing up. There was hardly one day that I didn’t vomit. My average weight is around 150 pounds, during chemotherapy I weighed 95 – 100 pounds.
Beside the common side effects of chemotherapy (loss of hair, fatigue, pain, nausea, and vomiting) I would get rashes all over my body. A vein in my left arm would bulge and it felt like my arm was broken, limiting about 50% of any arm movement.
I went to the ER a couple times during my two weeks between chemo cycles. One thing that helped me get through these hard times was keeping a notebook where I would write down ten things I was grateful for each day. Despite feeling terribly sick, I felt genuine happiness and peace. I will never forget one night when I was looking at myself in the mirror. I saw a hairless, skinny, deathly sick teenage boy. I smiled at myself and felt real inner peace. I learned then that no matter the circumstances of life we can still be happy. I believe my peace of mind came from my belief in God, doing my best to stay true to my morals, and the support I received from family, doctors, nurses, church leaders, and friends. Without these things cancer would have been much harder.
The response to the chemotherapy was good. After I finished my four rounds of chemotherapy, it was suggested by my oncologist and other doctors that I would need an open retroperitoneal lymph node dissection (O-RPLND) as well as a left radical orchiectomy. I met with several doctors to discuss the potential problems of an RPLND surgery. I was terrified when a doctor informed me that the procedure could result in infertility, an inability to ejaculate, or the inability to have an erection. My surgeon, Dr. John P. Stein, reassured me that I would be able to have an erection after the surgery. However, it was likely that a nerve would be cut during the surgery that would result in retrograde ejaculation (when semen is redirected to the bladder). I was not able to bank any sperm prior to my chemo treatments, after chemo my sperm count was zero.
The surgery was scheduled for November 21st, 2003. I was given around two months to regain strength and finish treatment for my blood clot.
The RPLND procedure was my hardest trial. I arrived at the USC Norris Cancer Center the day before the surgery. My anxiety and stress caused me to vomit. A nurse, who was taking my blood, saw how nervous I was and simply told me to trust in God. I had so much support from family and friends, but somehow that small gesture calmed me down.
My surgeon, an internationally recognized urologist, described my 8-hour surgery as an “exceedingly difficult operation”. Over 100 surgical staples were used to close my scar which extends from my waist line to directly under my left armpit. A part of my rib was removed during the surgery, which still causes me discomfort every day. My nerves that control ejaculation were damaged, which caused infertility problems and retrograde ejaculation.
After the surgery, I was in intensive care for three days with a ventilator. I remember hearing the man next to me constantly screaming in pain. After three days, the ventilator was removed and because of my shortness of breath I wasn’t allowed pain killers. The pain I felt after leaving the ICU was unlike anything else. My surgeon told me that it didn’t matter what happened to me in the future – I would never experience that much pain again in my life.
The week after my surgery was the hardest week of my life. I slowly began to recover from the surgery and enter into complete remission.
I spent my birthday and Thanksgiving in the hospital that year, so I was excited and determined to spend Christmas at home. The surgery and pain medication affected my digestive system and days before Christmas Eve I wasn’t able to hold down any food or water. I had gone a couple days without any food or water before telling my family on Christmas Eve that I knew I needed to go to the hospital. I spent two days in the hospital to recover. Thankfully that was my last hospital stay.
Cancer sucks! However, I am grateful for the life experiences I gained from going through it. I wouldn’t be who I am today without those trying moments.
In 2007, I met my wife Amanda. After three tries with IVF we were blessed with a beautiful baby girl, Caitlyn. She was born exactly 11 years after my cancer diagnoses.
Note: This post was written for Stripes of a Warrior.
]]>Here are some of my most used apps and extensions for Google Chrome:
![]() |
Adblock Plus: Blocks most annoying ads, malware, and tracking. |
![]() |
PushBullet: An app that links your computer with all your devices. |
![]() |
Pocket: Save articles, videos and more for later. |
![]() |
Feedly: All your favorite sites in one place. |
![]() |
Grammarly: Spell check and grammar check as you type online. |
![]() |
Bitly: URL shortening service. |
![]() |
Block site: Automatically blocks websites of your choice. |
![]() |
Tampermonkey: Inject additional JavaScript into web pages. |
| TrackingTime: Measure and manage time spent on projects. |
![]() |
Reddit Enhancement Suite: A suite of tools to enhance your Reddit browsing experience. |
![]() |
Google Calendar |
![]() |
Bookmark Manager |
![]() |
Chrome Remote Desktop |
![]() |
Google Cast |
![]() |
Google Dictionary |
![]() |
Google Translate |
![]() |
Hangouts |
![]() |
Advanced REST client: Create and test custom HTTP requests. |
|
Android SDK Search: Adds a “view source” link to pages on d.android.com |
![]() |
Chrome Apps & Extensions Developer Tools |
![]() |
Codota: Analyzes code snippets in web pages to show API docs. |
![]() |
Eye Dropper: Pick colors from web pages. |
|
JSONView: Validate and format JSON. |
![]() |
Web Developer: Adds a toolbar button with various web developer tools. |
In a game I’m currently working on (Lollipop Land) I set out to add more unique characters. The object of the game is to jump/fly your way through lollipops without hitting one or face planting onto the ground.
The next release will have at least 11 new characters. Each character is a set of PNGs that make up an AnimatedDrawable. The new characters are different shapes and sizes, thus adding complexity to when the character actually intersects with an obstacle in the game. After some research, I came across the convex hull algorithm. Ultimately, my goal was to eliminate any transparency in the image for the best precision when passing through obstacles in the game. The convex hull algorithm is exactly what I was looking for.
If you had an image or object and put a rubber band around that object, the convex hull would be the set of points at which the rubber band touched the object. Here is a more thorough definition:
In mathematics, the convex hull or convex envelope of a set X of points in the Euclidean plane or Euclidean space is the smallest convex set that contains X. For instance, when X is a bounded subset of the plane, the convex hull may be visualized as the shape formed by a rubber band stretched around X.
Formally, the convex hull may be defined as the intersection of all convex sets containing X or as the set of all convex combinations of points in X. With the latter definition, convex hulls may be extended from Euclidean spaces to arbitrary real vector spaces; they may also be generalized further, to oriented matroids.1, 2
First off, you need to load your bitmap or drawable into memory. Once we have a reference to the bitmap we can parse the bitmap pixel by pixel.3
ArrayList<Point> points = new ArrayList<Point>();
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
for (int x = 0; x < width; x++) {
int firstY = -1, lastY = -1;
for (int y = 0; y < height; y++) {
boolean transparent = (pixels[y * width + x] == Color.TRANSPARENT);
if (!transparent) {
if (firstY == -1) {
firstY = y;
}
lastY = y;
}
}
if (firstY != -1) {
points.add(new Point(x, firstY));
points.add(new Point(x, lastY));
}
}
The code above will give us a path around our bitmap, but the set of points will be much larger than desired. To
increase performance we can use the Quickhull algorithm. Quickhull is a method of computing the convex hull of a finite
set of points in n-dimensional space. It uses a divide and conquer approach similar to that of quicksort, from which its
name derives. Its worst case complexity for 2-dimensional and 3-dimensional space is considered to be
\(O(n\log(r))\), where n is the number of input points and r is the number of processed points.4
Here is my modified Quickhull class for Android:
/*
* Copyright (C) 2014 Jared Rummler <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ArrayList;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
/**
* Find points in convex hull using quick hull method
*/
public class QuickHull {
/** Returns the quick hull of a {@link Drawable}, which is scaled down by the size */
public static ArrayList<Point> quickHull(@NonNull Drawable drawable, int size) {
return quickHull(Bitmap.createScaledBitmap(drawableToBitmap(drawable), size, size, false));
}
/** Returns the quick hull of a {@link Drawable} */
public static ArrayList<Point> quickHull(@NonNull Drawable drawable) {
final ArrayList<Point> hull = new ArrayList<Point>();
final Bitmap bitmap = drawableToBitmap(drawable);
if (bitmap != null) {
hull.addAll(quickHull(bitmap));
}
return hull;
}
/** Returns the quick hull of a bitmap */
public static ArrayList<Point> quickHull(@NonNull Bitmap bitmap) {
final ArrayList<Point> points = new ArrayList<Point>();
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
final int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
for (int x = 0; x < width; x++) {
int firstY = -1, lastY = -1;
for (int y = 0; y < height; y++) {
final boolean transparent = (pixels[y * width + x] == Color.TRANSPARENT);
if (!transparent) {
if (firstY == -1) {
firstY = y;
}
lastY = y;
}
}
if (firstY != -1) {
points.add(new Point(x, firstY));
points.add(new Point(x, lastY));
}
}
return quickHull(points);
}
/** Returns a list of points in convex hull using quick hull method */
@SuppressWarnings("unchecked")
public static ArrayList<Point> quickHull(ArrayList<Point> points) {
final ArrayList<Point> convexHull = new ArrayList<Point>();
if (points.size() < 3) {
return (ArrayList<Point>) points.clone();
}
int minPoint = -1, maxPoint = -1;
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
for (int i = 0; i < points.size(); i++) {
if (points.get(i).x < minX) {
minX = points.get(i).x;
minPoint = i;
}
if (points.get(i).x > maxX) {
maxX = points.get(i).x;
maxPoint = i;
}
}
final Point a = points.get(minPoint);
final Point b = points.get(maxPoint);
convexHull.add(a);
convexHull.add(b);
points.remove(a);
points.remove(b);
ArrayList<Point> leftSet = new ArrayList<Point>();
ArrayList<Point> rightSet = new ArrayList<Point>();
for (int i = 0; i < points.size(); i++) {
Point p = points.get(i);
if (pointLocation(a, b, p) == -1) leftSet.add(p);
else rightSet.add(p);
}
hullSet(a, b, rightSet, convexHull);
hullSet(b, a, leftSet, convexHull);
return convexHull;
}
private static int distance(Point a, Point b, Point c) {
final int ABx = b.x - a.x;
final int ABy = b.y - a.y;
int num = ABx * (a.y - c.y) - ABy * (a.x - c.x);
if (num < 0) num = -num;
return num;
}
private static void hullSet(Point a, Point b, ArrayList<Point> set, ArrayList<Point> hull) {
final int insertPosition = hull.indexOf(b);
if (set.size() == 0) return;
if (set.size() == 1) {
final Point p = set.get(0);
set.remove(p);
hull.add(insertPosition, p);
return;
}
int dist = Integer.MIN_VALUE;
int furthestPoint = -1;
for (int i = 0; i < set.size(); i++) {
Point p = set.get(i);
int distance = distance(a, b, p);
if (distance > dist) {
dist = distance;
furthestPoint = i;
}
}
final Point p = set.get(furthestPoint);
set.remove(furthestPoint);
hull.add(insertPosition, p);
// Determine who's to the left of AP
final ArrayList<Point> leftSetAP = new ArrayList<Point>();
for (int i = 0; i < set.size(); i++) {
final Point m = set.get(i);
if (pointLocation(a, p, m) == 1) {
leftSetAP.add(m);
}
}
// Determine who's to the left of PB
final ArrayList<Point> leftSetPB = new ArrayList<Point>();
for (int i = 0; i < set.size(); i++) {
final Point m = set.get(i);
if (pointLocation(p, b, m) == 1) {
leftSetPB.add(m);
}
}
hullSet(a, p, leftSetAP, hull);
hullSet(p, b, leftSetPB, hull);
}
private static int pointLocation(Point a, Point b, Point p) {
int cp1 = (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);
return (cp1 > 0) ? 1 : -1;
}
private static Bitmap drawableToBitmap(@NonNull Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
final int height = drawable.getIntrinsicHeight();
final int width = drawable.getIntrinsicWidth();
if (width <= 0 || height <= 0) {
return null;
}
final Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
private QuickHull() {
throw new IllegalStateException("no instances");
}
}
Now with this helper class we can get the convex hull of a Bitmap on Android with a single line of code.
List<Point> hull = QuickHull.quickHull(bitmap);
Let’s test out the Google logo to see the “rubber band” in action.
Google Logo (Original Image)

Google Logo (With QuickHull)

1 Andrew, A. M. (1979), Another efficient algorithm for convex hulls in two dimensions, Information Processing Letters 9 (5): 216–219, 10.1016/0020-0190(79)90072-3
2 Brown, K. Q. (1979), Voronoi diagrams from convex hulls, Information Processing Letters 9 (5): 223–228, 10.1016/0020-0190(79)90074-7
3 Kaplan, Josh. “Brown CS: Android Attack!” : Image Transparency (aka an Absurd Application of Convex Hull). N.p., 22 Mar. 2010. Web.
4 Barber, C. Bradford; Dobkin, David P.; Huhdanpaa, Hannu (1 December 1996). “The quickhull algorithm for convex hulls” (PDF). ACM Transactions on Mathematical Software. 22 (4): 469–483.
]]>Lollipop Land is a fun game based off the Android 5.0 Easter Egg.

Fly bugdroid through the Android dessert forest, through the sea of swirly twirly lollipops. Jump your way through this delicious lollipop land.
This post will explain how my first game, Lollipop Land, came to be.
Something you may not know about Android is that each major release is named after sweet foods and candies, in alphabetical order. The first public release of Android was code-named Cupcake. Here is a chart I made for each Android version code-name (as of 2014):

“Easter eggs” are hidden symbols, messages and jokes worked into movies, books, paintings, video games and computer software—often intended as a little “reward” to viewers who are paying close attention or know where to look. And in fact, there’s probably an Easter egg in your Android device right now. — verizonwireless
Starting with Android version 2.3 (Gingerbread) Google started adding an “Easter egg” into each release. You can find the Easter egg by going into Settings, then About phone, and then rapidly tapping on Android version.
Gingerbread’s Easter egg was an Android mascot surrounded by zombies. Honeycomb’s Easter egg was an Android bee. The Ice Cream Sandwich Easter egg, dubbed “Nyandroid”, was based off the popular YouTube video Nyan Cat. Jelly Bean’s Easter egg consisted of tons of jelly beans floating around on the screen. The KitKat Easter Egg was a beautiful mosiac which displayed all the previous releases of Android, including some rare images which show what Google considered naming previous releases (Flan, JandyCane, and Key Lime Pie).
Android 5.0 Lollipop is the biggest update of Android to date. The Android blogosphere could not get enough of the rumors surrounding the next version of Android. If you watch any of the reviews of Android 5.0 on YouTube, chances are the reviewer showed off the new Easter egg.
When you first open the Easter egg you see a huge Lollipop. After clicking the Lollipop 6 times, followed by a long-click, a beautiful Lollipop world is displayed to the user. This Lollipop world was undoubtedly inspired by the 2014 hit game Flappy Bird. Instead of the bird, your player is the Android mascot (bugdroid). Instead of retro-themed pipes, the barriers are Lollipops. When you click the screen you automatically go into game-play. The object of the game is to pass through each Lollipop barrier by tapping on the screen to keep bugdroid from hitting the ground.
When I first saw the Lollipop Easter egg I immediately wanted to turn it into a full-fledged game—adding Google Play Games Services with leaderboards and achievements, different difficulty settings, sounds, and other features.
On November 3rd, 2014 Google pushed the Android 5.0 source code to AOSP. Now anyone could see how the developer team at Google created this lollipop world. In less than one day I had the first version of Lollipop Land on Google Play.
If you read the output given by logcat you can see which Intent is launched when you open the Easter egg. For Android 5.0 we can see the following output:
Displayed com.android.systemui/.egg.LLandActivity
The log shows us both the package and class name (<package>/<class>). We can see that this Activity resides in the SystemUI package. Since Android is open source we can find the source code for LLandActivity.java which is launched from PlatLogoActivity.java. LLandActivity simply shows a view which extends FrameLayout named LLand.
LLand uses new APIs that only exist on Android 5.0. In order to back-port this class to run on lower versions of Android some changes are needed. Some newer APIs used in LLand are VectorDrawable, setTranslationZ(float), ViewOutlineProviderget.getOutline(android.view.View, android.graphics.Outline), and others.
The images displayed in the game are drawn using the new VectorDrawable. First, I attempted to convert all the VectorDrawables to SVGs and use a third-party library which adds SVG support, like android-svg. This wasn’t working as expected so I ended up writing some code to convert the VectorDrawables to PNGs Overall, back-porting the game to Android 4.0+ was not very hard. After a couple of hours from when Android 5.0 source hit AOSP I already had the game running on lower-end devices.
Finding sounds for a game was more time-consuming than I expected. I spent several hours looking for sounds that had a license I could use on a game published on Google Play.
Google Play Services adds the ability to add achievements and a leaderboard to compete with friends. The only problem with Google Play Services is that… it is a monolith abomination (edit: not anymore). Google Play Services greatly increased the size of my APK and added, in my opinion, many unnecessary resources to my project. This was the most demanded feature, so, in the end, it was definitely worth it.
The most discussed topic around the game is how insanely difficult it is (which also makes it addictive). The original version seems almost impossible to get a score above 1 point. Lollipop Land has added difficulty levels, and I have other features planned for future releases. The game doesn’t require any permissions and is 100% completely free.
In less than one week Lollipop Land has had over 5,000 downloads with no marketing strategy. It was a fun side project for me that I hope you enjoy. If you haven’t tried it yet, go download it and see how many points you can get.
]]>Every known invention of mankind has started as a simple thought, an idea.
“What the mind of man can conceive and believe, it can achieve.” – Napoleon Hill
I have come to the conclusion that everyone has an idea for an app. When I share with others that I develop mobile applications the first response I usually receive is a new idea that is bound to revolutionize the world.
I honestly don’t know what to say when people share their idea. Some ideas are great, some have potential, and others are just plain horrible. Usually, the person sharing the idea hasn’t considered some basic questions.
Designing, developing, marketing, and publishing an app can cost more than you might expect. It is hard to estimate the cost of development and it will depend on what your requirements are. To get a rough estimate for development costs you should visit howmuchtomakeanapp.com.
If you don’t have a large budget for your app idea you may want to consider other options. Hiring less experienced developers can cut costs but is also a risky move. The best option, in my opinion, is to learn on your own. If you are truly passionate about your idea then you will do everything in your power to see that it comes to fruition. There are quite a few developers who started in their basement and now are multimillionaires.
A major portion of ideas I have heard have dealt with apps that are already on the market. The person who has the idea usually wants to re-create the app with additional features that he/she thinks would blow away the competition. This doesn’t mean that your idea is bad. However, if your current competition has a large user-base, many employees, and is well established then your chances of success are slim.
Other ideas I have heard are geared toward a niche market. I would assume that your end goal is to make a profit. If your target market is too small, the cost of development will be too large to make it a wise decision. There are hundreds of thousands of apps on the various app markets and it is becoming more difficult to become recognized. If you project that 1,000 – 5,000 people will use your app, then you need to come up with a strategy to at least break even.
It is becoming harder and harder to be found on Android and iOS. Without a good marketing strategy your time and money may go to waste. How will you market your app? Grassroots? Word of mouth? Paid advertising?
“Many eager entrepreneurs and developers choose to create mobile apps because they believe they can make “easy money”. Although there is plenty of money to be made from mobile apps, it doesn’t come easy. You must have a solid strategy in place in order to create a profitable app. Your revenue strategy should be integral to the app design process, not an afterthought.” – Benji Hyam
You should research and choose one of the following monetization methods: Paid Apps (Direct Sale), Freemium and Free-to-Play, In-App Purchases and Advertising, and Subscriptions.
I have asked several developers what turns them away when people share their app ideas. The most common responses were how the person approached the developer about the idea.
“I don’t want to share my idea because I’m afraid you might steal it.”
The developer will automatically think that listening to your idea is a waste of time.
“I’ll share my idea with you if you promise to give me x% of the profits.
This is a turn off. Please don’t think that just because you have a good idea entitles you to money.
Robin Williams was once asked by a reporter what he said to aspiring comedians who asked him if they should be a comedian.
Williams reportedly said, “I tell them no. Don’t do it.”
When asked why he would say such a thing he replied; “If they have the drive to make it; they’re not going to give a f*** about what I say. And if someone quits because I say that; then they weren’t going to make it anyway. I just saved that person from wasting their time.”
If you have the drive there is nothing stopping you from making your app idea a reality!
]]>