58 Commits

Author SHA1 Message Date
Siyamed Sinir
1d753f6fe9 Revert "Reduce memory usage of FontCollection."
This reverts commit c4b989fc812af6c94018bad2e30ed6a006e2f8f5.

Test: Manually tested
Bug: 34247671
Change-Id: I0510009b2deac784770f26059681b1980800abc8
2017-01-12 20:13:11 +00:00
Seigo Nonaka
c4b989fc81 Reduce memory usage of FontCollection.
Since switching to 64-bit devices, size_t is now a 64-bit integer.
FontCollection::Range uses two size_t integers but they just point to an index
in mFamilies. To reduce the memory usage, this CL changes the size_t integers to
uint8_t.

The maximum size of each integer in Range is the size of FontCollection::mFamilies.
The largest this can go is the system font list plus a user defined family, which
has 91 families. So an 8-bit integer should be enough.

With this change, about 84 KiB of memory will be saved per font collection. Since
eight font collections are created during bootstrap, about 670 KiB of memory will
be saved with this CL.

Bug: 33562608
Test: Ran FontCollection.collectionAllocationSizeTest on a 64-bit device.
      On my Nexus 5X, it changed from 327358 to 241342.

Change-Id: I9e01d237c9adcb05e200932401cb1a4780049f86
2017-01-06 17:27:14 +09:00
Mark Salyzyn
32c12c0ac8 resolve merge conflicts of 2377a00 to master
Test: build
Bug: 26552300
Bug: 31289077
Change-Id: I6181ae7e84f9bdcbed50841c70d07f6906a10eb7
2016-12-28 13:51:49 -08:00
Mark Salyzyn
555d84c6f9 minikin: Replace cutils/log.h with android/log.h or log/log.h
- replace cutils/log.h with android/log.h (main buffer logging)
- replace cutils/log.h with log.log.h (+SafetyNet logging)
- define LOG_TAG before use.

Test: compile
Bug: 26552300
Bug: 31289077
Change-Id: I7a4803dd66f31b7103e09e5ff5b8fa523fa0fd60
2016-12-27 10:10:18 -08:00
Yirui Huang
d478da324d Change language score calculation
Change language score calculation in the calculation of the font family.
Instead of language and script matching, a match in subtag is added.
In addition, a match in subtag has a higher priority than a match in
script. The score levels are divided into 5 score levels and the limit
of the number of font languages is changed to 12 from 17. Multiple
languages selection rule could to be added in the future.

Bug: 31608997
Test: Done by unittests.
Change-Id: I1e7177095f604fd1794bc99ca36c705dcb4c56e7
2016-12-06 18:17:54 +09:00
yirui
e1d7f6168a Parse Emoji subtag and store it to FontLanguage
Parse Emoji subtag and store into 4 different styles: default, text,
color and empty. Replace hasEmojiFlag function with getEmojiStyle to
get effective status according to script and subtag. However, score
calculation for the font selection needs to be completed in the next
stage. No performance regression is observed with this CL.

Bug: 31608997
Test: Done by unittests.
Change-Id: I923243641c946248dd5a0aa9fb9c940515310d34
2016-11-21 06:24:26 +00:00
Seigo Nonaka
4a4e6574c0 Fix lookup order for VS in itemization.
This is partial revert of Iced1349e3ca750821d8882c551551f65bb569794.

Due to sorting of target family vectors, the font family order from XML
settings file is broken. Making unique operation stable doesn't fix the
issue completely since some font families are appended for the fallback
which also breaks the original order.

By this change, itemization becomes 3x slower than before if variation
selector is appended.

Bug: 29585939
Change-Id: I7c1a8a57f04111a30cd41a5cd5bec25fcfb3972e
2016-09-15 16:23:40 +09:00
Roozbeh Pournader
b830102259 Revert "Lookup glyph from color emoji font before and after ZWJ." am: 1aa0c40db9 am: de728a34c9
am: f83d57f7e5

Change-Id: Iebf945839891cc1ab561cf424ef917ac15e08842
2016-08-11 23:40:20 +00:00
Roozbeh Pournader
1aa0c40db9 Revert "Lookup glyph from color emoji font before and after ZWJ."
This reverts commit 9431bb96406121d2eb3fda8ca8209edc434f96a0.

Bug: 30815709
Change-Id: I057d9bcd05246e58894abb4e9633bd10f6fab211
2016-08-11 21:03:00 +00:00
Seigo Nonaka
9431bb9640 Lookup glyph from color emoji font before and after ZWJ.
Unicode recommends that the zwj sequences should be emoji presentation
even if they don't have the proper U+FE0F. Thus always lookup the glyph
for the code point before and after zwj as if they have a U+FE0F
variation selector.

Bug: 30056627
Change-Id: I03958a92337eaba4a8dd9c5be824b2665aa4a103
2016-07-13 14:12:06 -07:00
Seigo Nonaka
c2642f9a33 Treat U+2695, U+2640, U+2642 as emoji characters.
Bug: 29885295
Change-Id: I1bf191a46d05e7099265d863bae0523c50817d0b
2016-07-13 14:05:02 -07:00
Seigo Nonaka
fab99dde4b Add some gender balanced components in to the sticky whitelist.
FEMALE SIGN(U+2640), MALE SIGN(U+2642), StAFF OF AESCULAPIUS(U+2695)
will be used as the ZWJ sequenced in gender balanced emoji sequence.
To be in the same run with ZWJ, mark these emoji as sticky chracters.

With this fix, Female police officer sequence will be shown correctly
regardless of VS16.

Bug: 30026374
Change-Id: I503fc061eaa943d45208bb69e885151610c430ce
2016-07-13 14:01:41 -07:00
Seigo Nonaka
98487de547 Lookup glyph from color emoji font before and after ZWJ.
Unicode recommends that the zwj sequences should be emoji presentation
even if they don't have the proper U+FE0F. Thus always lookup the glyph
for the code point before and after zwj as if they have a U+FE0F
variation selector.

Bug: 30056627
Change-Id: I03958a92337eaba4a8dd9c5be824b2665aa4a103
2016-07-12 10:07:19 +09:00
Seigo Nonaka
1946f48e84 Treat U+2695, U+2640, U+2642 as emoji characters.
Bug: 29885295
Change-Id: I1bf191a46d05e7099265d863bae0523c50817d0b
2016-07-11 15:27:05 +09:00
Seigo Nonaka
435076ff2e Add some gender balanced components in to the sticky whitelist.
FEMALE SIGN(U+2640), MALE SIGN(U+2642), StAFF OF AESCULAPIUS(U+2695)
will be used as the ZWJ sequenced in gender balanced emoji sequence.
To be in the same run with ZWJ, mark these emoji as sticky chracters.

With this fix, Female police officer sequence will be shown correctly
regardless of VS16.

Bug: 30026374
Change-Id: I503fc061eaa943d45208bb69e885151610c430ce
2016-07-08 15:49:50 +09:00
Seigo Nonaka
14e2d136aa Always use minikin namespace.
Here is a new policy of the namespace of minikin.
- All components should be in minikin namespace.
- All tests are also in minikin namespace and no anonymous namespace.

Bug: 29233740
Change-Id: I71a8a35049bb8d624f7a78797231e90fed1e2b8c
2016-06-11 00:11:17 +09:00
Seigo Nonaka
994aa84f7b Returns hasVariationSelector true for VS15/VS16
Minikin has a special font fallback for VS15/VS16, so
hasVariationSelector for emojis with VS15/VS16 should always return
true.

Bug: 27531970
Change-Id: Ieebd58f48b135b6ec50d999df68dcc09b1284606
2016-04-15 12:45:04 +09:00
Seigo Nonaka
f3afe92def Support multiple locales for font language settings.
Some fonts support multiple scripts, for example, some fonts for
Korean supports not only "Kore" but also "Jamo".

To select fonts based on their multiple languages, this CL introduces
the following changes:
- Compares all languages of the font family and use the maximum score
  for font selection.
- Even if each language of the font family doesn't support the requested
  language, the font get score of 2 if the requested font is covered by
  all of the languages of the font family. For example, the font for
  "ko-Hang,ko-Hani" gets score of 2 for the requested language "ko-Kore".

Bug: 26687969

Change-Id: I7f13b51464c9b01982bb573251d77052b9ddbd70
2016-04-04 22:31:16 +09:00
Roozbeh Pournader
16ed4ef07e Try putting combining marks in the same font run
Indic combining marks, when combined with a common character such as
a hyphen or a dotted circle, used to get rendered in a different font
due to the greedy algorithm used in determining runs, which resulted
in the base character and the combining mark getting rendered in
separate font runs, resulting in a dotted circle appearing in phrases
such as "100-ാം" (0031 0030 0030 002D 0D3E 0D02).

This change makes combining marks change the font run of the base
character if the base character is supported in the same font as the
combining mark, similar to the support for emoji modifiers and the
combining keycap.

Bug: 25036888
Bug: 24535344
Change-Id: I8e2798e8ecb8efaf723a0fd02c05c6fbdef8b365
2016-03-30 17:48:34 -07:00
Seigo Nonaka
cee83d4032 Suppress log span due to returning null for itemize result.
Bug: 26808815
Change-Id: I2a5a52f2c441d27c7ef270342b4ef93c3de9e56e
2016-03-03 15:51:55 -08:00
Seigo Nonaka
0036da164e Use color font if skin tone is specified.
If skin tone is specified, the base emoji should be emoji style even
if it is text presentation default emoji.

This patch also removes wrong test case which expects default emoji
presentation but it is controlled by family order in /etc/fonts.xml
and there is no special logic for default presentation in minikin.
Thus the default presentation unit test should not be in minikin.

Bug: 27342346

Change-Id: I74a2b2feab4d559535049e368cfd833063cce81c
2016-02-26 11:26:30 +09:00
Seigo Nonaka
6b1c227da6 Improve Paint.measureText and Paint.hasGlyph for variation sequences.
Before this patch, the font fallback chain iterated all installed font
families if a variation selector was specified.

This CL narrows down the range of iteration.
To decide the font family for the variation sequence, we need to search
for both the variation sequence and its base code point.
The new range of the iteration is a union of them.

With this change, the running time of Paint.hasGlyph for the variation
sequence improves 50% and the running time of Paint.measureText for the
variation sequence improves 40% for the large text case on Nexus 6
userdebug.

Bug: 26784699
Bug: 11750374

Change-Id: Iced1349e3ca750821d8882c551551f65bb569794
2016-02-17 16:01:20 +09:00
Seigo Nonaka
89e80237bc Improve Paint.hasGlyph performance by caching hb_font_t
It turned out that hb_font_t creation is not a lightweight operation.
Especially, Paint.hasGlyph creates hb_font_t for all existing fonts
every time. To improve the performance, cache hb_font_t instead
of hb_face_t.

Note that to calculate horizontal advance, MinikinPaint needs to be
associated with hb_font_t by calling hb_font_set_funcs. With this patch,
hb_font_set_funcs may be called multiple times for the same hb_font_t
object. However this is not an issue since MinikinPaint is unique
during layout.

Bug: 26784699

Change-Id: I516498ae9f0127d700fc9829327e9789845a1416
2016-02-04 12:26:10 +09:00
Seigo Nonaka
6f9966ea7c Introduce multiple language based font fallback.
The motivation of this CL is enhance the font fallback score design
to support multiple language font fallback.

This CL contains following changes:
- Break language based font score into two: script-based score and
  primary-language-based score.
- The primary-language-based score is 0 if the script-based score is 0.
  If the script-based score is not 0 and the primary language is the
  as same as the requested one, the font gets an extra score of 1.
- The language score gets a higher multiplier for languages higher in
  the locale list.

Bug: 25122318
Bug: 26168983
Change-Id: Ib999997a88e6977e341f4c325e2a1b41a59db2d5
2016-01-15 14:35:14 +09:00
Seigo Nonaka
7564b7fd5b Merge "Fix race condition in Paint.hasGlyph()" 2016-01-06 06:00:38 +00:00
Seigo Nonaka
a6f5c46836 Fix race condition in Paint.hasGlyph()
The caller of FontFamily::hasVariationSelector needs to acquire the
lock before calling it, but FontCollection::hasVariationSelector
didn't acquire the lock. This caused a race condition.
This CL fixes this race condition.

Also, it turned out that assertMinikinLocked didn't assert even on
eng or userdebug device. This CL enables assertion on eng and userdebug
device since this assertion must be treated as bug.

BUG: 26323806

Change-Id: I9c4b1e1f09c6793e387fbdb8bb654cc0a13c65d5
2016-01-06 03:21:37 +00:00
Seigo Nonaka
198b46f1fe Save all kind of script tags into FontLanguage.
This is 2nd attempt of I8df992a6851021903478972601a9a5c9424b100c.

The main purpose of this CL is expanding FontLanguage to be able to
save full script tag. Previously, FontLangauge kept only limited script
tags. With this CL, FontLanguage keeps all script tags.

This CL contains the following changes:
- FontLanguage changes:
-- Moved to private directory not to be instantiated outside of Minikin.
-- Removed bool(), bits(), FontLanguage(uint32_t) methods which are no
   longer used.
-- Change the FontLanguage internal data structure.
-- Introduces script match logic.

- FontLanguages changes:
-- Moved to private directory not to be instantiated outside of Minikin.
-- This is now std::vector<FontLanguage>

- FontLanguageListCache changes:
-- Now FontLanguageListCache::getId through
   FontStyle::registerLanguageList is the only way to instantiate the
   FontLanguage.
-- Normalize input to be BCP47 compliant identifier by ICU.

Bug: 26168983
Change-Id: I431b3f361a7635497c05b85e8ecbeb48d9aef63e
2016-01-05 14:00:32 +09:00
Bart Sears
6c4c098cbd Revert "Save all kind of script tags into FontLanguage."
This reverts commit 5e995fb850c2b32631914c3815dfb421855fba9b.

Change-Id: I761e0e41906742fbe3d3ac34170af3101e18042a
2015-12-22 09:06:03 +00:00
Seigo Nonaka
5e995fb850 Save all kind of script tags into FontLanguage.
The main purpose of this CL is expanding FontLanguage to be able to
save full script tag. Previously, FontLangauge kept only limited script
tags. With this CL, FontLanguage keeps all script tags.

This CL contains the following changes:
- FontLanguage changes:
-- Moved to private directory not to be instantiated outside of Minikin.
-- Removed bool(), bits(), FontLanguage(uint32_t) methods which are no
   longer used.
-- Change the FontLanguage internal data structure.
-- Introduces script match logic.

- FontLanguages changes:
-- Moved to private directory not to be instantiated outside of Minikin.
-- This is now std::vector<FontLanguage>

- FontLanguageListCache changes:
-- Now FontLanguageListCache::getId through
   FontStyle::registerLanguageList is the only way to instantiate the
   FontLanguage.
-- Normalize input to be BCP47 compliant identifier by ICU.

Bug: 26168983
Change-Id: I8df992a6851021903478972601a9a5c9424b100c
2015-12-22 09:34:04 +09:00
Seigo Nonaka
43bb9743ca Remove script matching score from the font selection fallback.
Removing the extra score of 2 for the script matching from the font
fallback score calculation.  If the two langauges have different
scripts, we should treat them as different languages.

Change-Id: Ie0d6f27bd1086248895935a7bd01b5d404044ad0
2015-12-10 18:41:03 -08:00
Seigo Nonaka
6d9dcd2cf3 Introduce FontLanguageListCache.
FontLanguageListCache is an intentionally leaky singleton and its
internal cache won't be purged.

BUG: 25122318

Change-Id: I272097e979fe44b83fd86822235350e12eda8f51
2015-12-08 18:49:18 -08:00
Seigo Nonaka
369d2d44cb Select emoji font based on variation selectors.
If U+FE0E is appended to the emoji code point, the glyph should have a
text presentation.
On the other hand, if U+FE0F is appended to the emoji code point, the
glyph should have an emoji presentation.

Bug: 11256006
Change-Id: I5187d44500b13a138e7ffbcf2c72e2da06374c8c
2015-12-07 16:49:16 -08:00
Seigo Nonaka
66a34a04ab Merge "Search all families instead of using mRanges for variation sequence." 2015-11-20 05:46:31 +00:00
Seigo Nonaka
fc119c68f5 Search all families instead of using mRanges for variation sequence.
To optimize the font family search, mRanges is used for narrowing down
the search range. However, mRanges is constructed from format 4 or
format 12 entries. So, if the font supports a variation sequence but doesn't
support the base character of the sequence, the font may not be listed in
mRanges.

The proper way to fix this issue is using format 14 subtable information
for mRanges construction. However, this is not a trivial work since currently
we rely on HarfBuzz for variation sequence lookup and it doesn't provide any
API for retrieving coverage information.

Thus, as the quick fix, iterate all font families in font fallback chain if
the variation sequence is specified.

Change-Id: I278da84be8fb8f553590e2e42ed450b7e4a34eca
2015-11-19 17:14:59 +09:00
Seigo Nonaka
80d113bcd4 Introduce FontCollection::hasVariationSelector method.
To implement Paint.hasGlyph(), we need a new method to ask the
FontCollection if it has a glyph for the code point and variation
selector pair.

Bug: 11256006
Change-Id: Ie4185c91bcaa4d01aee6beb97784b1f9d2a88f12
2015-11-19 17:01:46 +09:00
Seigo Nonaka
3dd8757fcf Fix invalid decrement range of KEYCAP handling in itemize.
This issue was introduced by I22ce0e9eadc941f84e3a9b23462f194e51dd7180.
Need to decrement the two utf16 chars in KEYCAP handling.

To add unit tests, this CL also addresses the Bug: 24184208 by
introducing self built fonts since there is no good example in system
installed fonts.

Bug: 24184208
Change-Id: I23fa008adbaced78a3cb96442a6bc8892ab84ce8
2015-11-13 14:39:06 +09:00
Seigo Nonaka
bae3476829 Add -Werror -Wall -Wextra to compiler option.
This is 2nd trial of I30a0914a4633bd93eb60957cdf378770f04d8428

- To suppress noisy unused parameter warnings, comment out unused
  arguments.
- Add -Werror for suppressing further warning.
- Add -Wall -Wextra for safety.
- Use "z" prefix for format string of size_t.

Verified that compile succeeded on all arm,arm64,mips,x86,x86_64.

Change-Id: I7ad208464486b8a35da53929cb1cfe541ed0052f
2015-10-28 04:52:49 +00:00
Seigo Nonaka
bbdd73ec07 Support Variation Selector in font selection.
This CL contains the following changes:
- Add a variation selector argument into getFamilyForChar to be able to
  select fonts which support variation selector.
- In case no fonts support the codepoint and variation selector pair,
  add a fallback rule which selects font family with ignoring variation
  selector.
- Change FontCollection::itemize to not change the font family
  immediately preceding a variation selector.
- Introduce unit tests for variation selectors.

With this CL, TextView can render the variation selectors correctly.

Bug: 11256006
Change-Id: I22ce0e9eadc941f84e3a9b23462f194e51dd7180
2015-10-20 12:34:40 +09:00
Seigo Nonaka
0f2a025d13 Introduce FontFamily::hasVariationSelector
This CL introduces new method hasVariationSelector into FontFamily but it
is not used in production code. So no behavior changes are expected.

This CL contains the following changes:
- Introduce hasVariationSelector which returns true if the corresponding
  font has a glyph for a code point and variation selector pair.
- Introduce purgeHbFontCache since hb_face_t won't be released by
  keeping hb_font_t.
- Introduce unit tests with self-built font.

Change-Id: I659a6d03d9ec446b409e1fba2758452abb9f44fa
2015-10-12 18:53:45 +09:00
Raph Levien
90a09c3f36 Improve fallback where explicit variant is not given
In computing scores for which fallback font to choose, a match of a
variant given explicitly in the xml config file scores higher than a
family with no explicit variant. One consequence is that U+2010
HYPHEN is chosen from the Naskh Arabic font in the fallback case.

This patch scores families with no variants as a match (effectively
the same as if the xml file specified both variants). Thus, it will
choose the first matching font (Roboto), which is a better choice.

This patch also revises the list of "sticky" characters to include
various hyphens, so Arabic (and potentially other scripts) text that
includes hyphens can access the script-specific variants matched to
the underlying text.

Bug: 22824219
Change-Id: I6ec1043037f89cad50ca99ac24c473395546bcdf
2015-07-29 14:36:33 -07:00
Andreas Gampe
cb20a2f0b3 Minikin: Remove unused variables, fix init order
For build-system CFLAGS clean-up, fix unused variables.

Reorder initializer list to initialize in the order of member
declarations.

Change-Id: I64358b2dcf0e39d0f4e18fdc3473de867f84fcba
2014-12-03 14:20:11 -08:00
Raph Levien
13f1aae02b Move coverage bitmap from FontCollection to FontFamily
This will significantly reduce memory usage and also speed the creation
of new font families. In particular, the coverage bitmaps for the fonts
in the fallback stack will be computed once in the Zygote, rather than
separately in each app process.

Bug: 17756900
Change-Id: I66f5706bddd4658d78fe5b709f7251ca9d2ff4f8
2014-12-03 12:48:20 -08:00
Raph Levien
997c799e3e Try Unicode decomposition for selecting fallback font
This patch finds an appropriate fallback font in the case where no font
directly maps the requested character, but a font does exist for the
character's canonical decomposition. This yields correct rendering of
compatibility characters such as U+FA70.

Bug: 15816880
Bug: 16856221
Change-Id: Idff8ed6b942fec992a0815a32028b95af091d0ee
2014-08-26 22:20:16 -07:00
Behdad Esfahbod
f952161b87 Choose same font for Emoji keycap and its base character
The U+20E3 COMBINING KEYCAP is used in our fonts to generate an emoji
rendering of ASCII numbers and letters through GSUB.  For that to work
we need to choose the same (Emoji) font for the character coming
*before* the COMBINING KEYCAP character.

This is a special-case of a broader need to choose fonts per grapheme
cluster as opposed to per character, but for now, special-case U+20E3.

Bug: 7557244
Change-Id: I958e5a01068df8495bbb9bc3b9ed871cea1838b6
2014-08-08 15:37:28 -04:00
Raph Levien
156acb18f5 Assign non-coverage font runs to base font
When a run has no cmap coverage in any font, use the base font. Most of
the time, this will cause rendering of the .notdef glyph, which is
preferable to displaying nothing. In some cases, Harfbuzz may be able to
decompose the characters (not in the cmap) to ones that are, in which
case we'll render those, as long as they're in the base font.

Bug: 6629748
Bug: 15816880
Change-Id: Ibb1b9242c83626e0c7db363ad65ce44a967a005e
2014-07-09 09:18:15 -07:00
Raph Levien
bb601b67dd Make font runs less sticky
Fixes b/15734816 In the text "Wi-Fi", "-Fi" appears bolder than "Wi"

The problem was caused by "stickiness" in choosing fonts, where layout
would prefer using a font used for preceding characters as long as it
mapped the following characters in a run, in favor of the "best match"
rules. This patch adds a whitelist for making the stickiness more
conservative, only applying it for characters necessary for correct
shaping (ZWJ and ZWNJ in particular) and basic punctuation, where it is
desirable to match the style of the preceding text.

Change-Id: I1cf116879f074a5a71c351846707bfdd07b0d320
2014-06-19 09:03:01 -07:00
Raph Levien
bd36ec766a Fix missing text on nonexistent font file
Fix for bug 15570313 "Missing text on nonexistent font file"

This patch makes sure that the lastChar and mInstances arrays are in
sync with each other even when a FontFamily being added has no valid
fonts in it. Previously, when they got out of sync, unicode coverage
calculation would be wrong, resulting in missing text.

Change-Id: I69c727ef69e2c61e2b2d6b81d5a28c806327f865
2014-06-11 16:03:49 -07:00
Raph Levien
9a5f713add Support for fake bold and italics
This patch adds support for computing when fake bold and fake italics
are needed (because the styles are requested but not provided by the
matching FontFamily), and providing them as part of the layout result.

Part of the fix for bug 15436379 Fake bold doesn't fully work (Minikin)

Change-Id: I180c034b559837943673b5c272c8e890178dff0d
2014-06-10 11:59:29 -07:00
Raph Levien
89566f0ada Add baseFont method to FontCollection
This patch adds a method to retrieve the base font from a
FontCollection, which is useful when querying global font metrics.

Part of the fix for bug 15467288 "Inconsistent line heights on
Minikin builds"

Change-Id: I268ae5128d0852a020d746bc22af81fc1a623228
2014-06-06 17:03:33 +00:00
Raph Levien
066e8575af Fix ZWJ not working for Indic fonts
This is a fix for bug 15185229 ZWJ not working in Sinhala and Kannada.

Indic fonts (unlike Arabic) require the entire string, including ZWJ,
to be passed to Harfbuzz; it's not enough for the ZWJ to be present in
the context. The solution is to be "sticky" in font itemization,
continuing to use the same font as long as it has Unicode coverage.

Change-Id: I7673bc56fbda09f1e1a4582e8d88342343b706f1
2014-05-29 15:16:32 -07:00