Implemented phutil_utf8_is_combining_character().

Summary: Implemented phutil_utf8_is_combining_character(), which returns true if an input character is a combining character.

Test Plan: Unit test: testUTF8IsCombiningCharacter().

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin, AnhNhan

Maniphest Tasks: T2379

Differential Revision: https://secure.phabricator.com/D5981
Implemented phutil_utf8_combined().

Summary: A function which splits a given UTF-8 string into an array of characters without splitting the combined characters.

Test Plan: Unit tests.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin, AnhNhan

Maniphest Tasks: T2379

Differential Revision: https://secure.phabricator.com/D6011
Provide the ability to set an alter-operation cost to PhutilEditDistanceMatrix

Summary:
In Arcanist, we currently price altering the edit operation so that strings like `(x)` vs `((x))` get analyzed as `isssi` instead of `issis` (that is, the first and last parens are highlighted as "new", rather than the first open and first close paren) which is better for human viewers.

Support this in PhutilEditDistanceMatrix.

Test Plan: Provided an alter cost in `arc` and ran the tests. They pass after this change.

Reviewers: btrahan, Afaque_Hussain

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2379

Differential Revision: https://secure.phabricator.com/D6013
Provide onboard optimizations for strings with similar prefixes and suffixes in PhutilEditDistanceMatrix

Summary: We can evaluate similar prefixes and suffixes in O(1). Provide this optimization within PhutilEditDistanceMatrix.

Test Plan: Ran unit tests.

Reviewers: btrahan, Afaque_Hussain

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2379

Differential Revision: https://secure.phabricator.com/D6014
Provide maximum comparison length onboard PhutilEditDistanceMatrix

Summary: After some maximum length, we bail out rather than compute the acutal edit distance because the time and memory complexity grows nonlinearly. Bring this check onboard PhutilEditDistanceMatrix.

Test Plan: Added and ran unit tests.

Reviewers: btrahan, Afaque_Hussain, ivane2004

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2379

Differential Revision: https://secure.phabricator.com/D6015
Fixing phutil_utf8_shorten().

Summary: Fixed phutil_utf8_shorten() to be combining character aware.

Test Plan: Unit tests. However, I think I may have not added enough test cases.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin, AnhNhan

Maniphest Tasks: T2379

Differential Revision: https://secure.phabricator.com/D6025
Add Filesystem::resolveBinary to lookup full path to binary file in PATH

Summary:
Arising out of an issue with D6070, I noticed that `where` on Windows actually returns all of the entries in PATH that match, rather than just the first.  There's three places in the code that use `where` directly, one of which is in phutil for `Filesystem::binaryExists` (where the semantics don't affect it).  The other two cases exist in Arcanist; the one introduced by D6070 and one in the JSHint linter.

This adds a `Filesystem::resolveBinary` method which is aware of the semantics of `where` on Windows and `which` on Linux.  I'm recommending that code use this method to determine absolute paths to binaries in the PATH so that we don't encounter the same issue as occurred in D6070.

Test Plan:
Run the `resolveBinary` unit tests.  The other unit tests for Filesystem are failing on my Windows box, presumably because they're trying to do UNIXy things.

The other thing you can do is replace the explicit usage of where with `Filesystem::resolveBinary`, like the place it's used in D6070 and confirm that it works as expected.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T3272

Differential Revision: https://secure.phabricator.com/D6077
Minor, fix a trim() issue with resolveBinary() on non-Windows systems.
Add a simple interface to abstract database escaping from aphront

Summary: Currently the qsprintf require an AphrontDatabaseConnection to escape strings which prevents others from using qsprintf without using aphront.  Instead, this creates an interface that the AphrontMySQLDatabaseConnection implements that then allows any implementer to use qsprintf.

Test Plan: Not actually sure how to test this.  @epriestley: Can you suggest some proper ways to test this besides "use phabricator"?

Reviewers: epriestley

CC: aran, Korvin

Differential Revision: https://secure.phabricator.com/D6123
Fix some lint warnings in libphutil

Summary: Lint.

Test Plan: Lint.

Reviewers: chad

Reviewed By: chad

CC: aran

Differential Revision: https://secure.phabricator.com/D6125
Improve invalid workflow message.

Summary: Given an invalid workflow, show an error message which lists available commands.

Test Plan: Try specifying an invalid workflow.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin, AnhNhan

Maniphest Tasks: T3040

Differential Revision: https://secure.phabricator.com/D6129
Improve performance of phutil_utf8_shorten()

Summary:
This function is a little slower and more complex than necessary:

  - If the string to shorten has fewer bytes than the maximum length, it certainly has fewer characters, and we can skip all the expensive utf8 operations.
  - If the terminal is longer than the maximum length, just return it unmodified. Throwing is messy and excessively strict, and we need to do expensive utf8 operations early in the function to ensure we throw consistently.

Test Plan: This is well-covered by unit tests.

Reviewers: chad, btrahan

Reviewed By: chad

CC: aran

Differential Revision: https://secure.phabricator.com/D6182
Make phutil_tag() / phutil_escape_html() 10-15% faster

Summary:
These numbers are a bit rough, but they seem to make a difference. Total weight of my test page (Maniphest task list) dropped from ~194ms to ~170ms. Time spent in phutil_tag() dropped from 105-110ms to 90ms.

This also cleans up the call graph for xhprof a bit (e.g., removes 1,300 calls to array_map()). Generally, `foreach(...)` is faster than `array_map(...)` (at least for small inputs, and at least on Zend PHP) as we avoid paying for function call overhead.

Test Plan: Loaded various pages. There should be no functional changes.

Reviewers: btrahan, chad, vrana

Reviewed By: chad

CC: aran

Differential Revision: https://secure.phabricator.com/D6183
Provide an AuthProvider skeleton in libphutil

Summary: Ref T1536. One of the major issues with authentication today is the tight coupling between provider APIs (e.g., how you figure out a user's account ID) and Phabricator-specific configuration (like whether a specific provider is enabled or not). To remedy this, I'm splitting auth providers apart into libphutil -- they have the provider-specific code which knows the OAuth/LDAP/OpenID protocols. The configuration and policy code will layer on top of them intead of being part-and-parcel.

Test Plan: Static only; this code is not reachable.

Reviewers: btrahan, chad, rezanachmad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6155
Add diagnostics to LDAPAdapter

Summary: Ref T1536. Provides diagnostics support for LDAP.

Test Plan: Ran `bin/auth ldap`, see next diff.

Reviewers: mbishopim3, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6217
Restore/respect "require secure browsing" for Facebook (libphutil)

Summary: Ref T1536. Facebook use this OAuth option which impacts only Facebook, but since it's auth related we should probably grandfather it in. See next diff for the Phabricator part.

Test Plan: Configured / force triggered it, got told ot turn on secure browsign.

Reviewers: chad, btrahan

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6223
Fix OAuth profile pictures for FB

Summary: Ref T1536. Older versions of this code had a multi-parameter accessor for the data, but this is essentially the only callsite any provider has for that so the new ones don't.

Test Plan: {F46833}

Reviewers: wez, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6233
Fix LDAP selection of DN after searching

Summary: Ref T1536. The "dn" property is unusual. Add code to find it.

Test Plan: Walked through this with @staticshock, who verified the fix.

Reviewers: staticshock, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6235
Expand LDAP auth API

Summary: Ref T1536. Support LDAP import somewhat better so I can nuke more code.

Test Plan: See next diff. Performed LDAP import.

Reviewers: btrahan, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6242
Add Asana and Amazon OAuth adapters

Summary:
Ref T1536. Ref T2852. These are pretty straightforward, except:

  - Amazon requires HTTPS, and won't let you make an app without an HTTPS callback URI.
  - Asana requires "Authorization:" instead of "?access_token" for authorization.

Test Plan: Created Amazon and Asana providers and used them to log in / register.

Reviewers: btrahan, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1536, T2852

Differential Revision: https://secure.phabricator.com/D6248