couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From beno...@apache.org
Subject [42/52] [partial] move src/* to the root
Date Sun, 12 Jan 2014 12:40:07 GMT
http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch/src/couch_util.erl
----------------------------------------------------------------------
diff --git a/apps/couch/src/couch_util.erl b/apps/couch/src/couch_util.erl
new file mode 100644
index 0000000..f4d66ef
--- /dev/null
+++ b/apps/couch/src/couch_util.erl
@@ -0,0 +1,488 @@
+% 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.
+
+-module(couch_util).
+
+-export([start_app_deps/1, ensure_started/1]).
+-export([priv_dir/0, normpath/1]).
+-export([should_flush/0, should_flush/1, to_existing_atom/1]).
+-export([rand32/0, implode/2]).
+-export([abs_pathname/1,abs_pathname/2, trim/1]).
+-export([encodeBase64Url/1, decodeBase64Url/1]).
+-export([validate_utf8/1, to_hex/1, parse_term/1, dict_find/3]).
+-export([get_nested_json_value/2, json_user_ctx/1]).
+-export([proplist_apply_field/2, json_apply_field/2]).
+-export([json_decode/1]).
+-export([to_binary/1, to_integer/1, to_list/1, url_encode/1]).
+-export([verify/2,simple_call/2,shutdown_sync/1]).
+-export([get_value/2, get_value/3]).
+-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
+-export([reorder_results/2]).
+-export([url_strip_password/1]).
+-export([encode_doc_id/1]).
+-export([with_db/2]).
+-export([rfc1123_date/0, rfc1123_date/1]).
+
+-include("couch_db.hrl").
+
+% arbitrarily chosen amount of memory to use before flushing to disk
+-define(FLUSH_MAX_MEM, 10000000).
+
+%% @spec start_app_deps(App :: atom()) -> ok
+%% @doc Start depedent applications of App.
+start_app_deps(App) ->
+    application:load(App),
+    {ok, DepApps} = application:get_key(App, applications),
+    [ensure_started(A) || A <- DepApps],
+    ok.
+
+%% @spec ensure_started(Application :: atom()) -> ok
+%% @doc Start the named application if not already started.
+ensure_started(App) ->
+    case application:start(App) of
+	ok ->
+	    ok;
+	{error, {already_started, App}} ->
+	    ok
+    end.
+
+priv_dir() ->
+    case code:priv_dir(couch) of
+        {error, _} ->
+            %% try to get relative priv dir. useful for tests.
+            EbinDir = filename:dirname(code:which(?MODULE)),
+            AppPath = filename:dirname(EbinDir),
+            filename:join(AppPath, "priv");
+        Dir -> Dir
+    end.
+
+% Normalize a pathname by removing .. and . components.
+normpath(Path) ->
+    normparts(filename:split(Path), []).
+
+normparts([], Acc) ->
+    filename:join(lists:reverse(Acc));
+normparts([".." | RestParts], [_Drop | RestAcc]) ->
+    normparts(RestParts, RestAcc);
+normparts(["." | RestParts], Acc) ->
+    normparts(RestParts, Acc);
+normparts([Part | RestParts], Acc) ->
+    normparts(RestParts, [Part | Acc]).
+
+% works like list_to_existing_atom, except can be list or binary and it
+% gives you the original value instead of an error if no existing atom.
+to_existing_atom(V) when is_list(V) ->
+    try list_to_existing_atom(V) catch _:_ -> V end;
+to_existing_atom(V) when is_binary(V) ->
+    try list_to_existing_atom(?b2l(V)) catch _:_ -> V end;
+to_existing_atom(V) when is_atom(V) ->
+    V.
+
+shutdown_sync(Pid) when not is_pid(Pid)->
+    ok;
+shutdown_sync(Pid) ->
+    MRef = erlang:monitor(process, Pid),
+    try
+        catch unlink(Pid),
+        catch exit(Pid, shutdown),
+        receive
+        {'DOWN', MRef, _, _, _} ->
+            ok
+        end
+    after
+        erlang:demonitor(MRef, [flush])
+    end.
+
+
+simple_call(Pid, Message) ->
+    MRef = erlang:monitor(process, Pid),
+    try
+        Pid ! {self(), Message},
+        receive
+        {Pid, Result} ->
+            Result;
+        {'DOWN', MRef, _, _, Reason} ->
+            exit(Reason)
+        end
+    after
+        erlang:demonitor(MRef, [flush])
+    end.
+
+validate_utf8(Data) when is_list(Data) ->
+    validate_utf8(?l2b(Data));
+validate_utf8(Bin) when is_binary(Bin) ->
+    validate_utf8_fast(Bin, 0).
+
+validate_utf8_fast(B, O) ->
+    case B of
+        <<_:O/binary>> ->
+            true;
+        <<_:O/binary, C1, _/binary>> when
+                C1 < 128 ->
+            validate_utf8_fast(B, 1 + O);
+        <<_:O/binary, C1, C2, _/binary>> when
+                C1 >= 194, C1 =< 223,
+                C2 >= 128, C2 =< 191 ->
+            validate_utf8_fast(B, 2 + O);
+        <<_:O/binary, C1, C2, C3, _/binary>> when
+                C1 >= 224, C1 =< 239,
+                C2 >= 128, C2 =< 191,
+                C3 >= 128, C3 =< 191 ->
+            validate_utf8_fast(B, 3 + O);
+        <<_:O/binary, C1, C2, C3, C4, _/binary>> when
+                C1 >= 240, C1 =< 244,
+                C2 >= 128, C2 =< 191,
+                C3 >= 128, C3 =< 191,
+                C4 >= 128, C4 =< 191 ->
+            validate_utf8_fast(B, 4 + O);
+        _ ->
+            false
+    end.
+
+to_hex([]) ->
+    [];
+to_hex(Bin) when is_binary(Bin) ->
+    to_hex(binary_to_list(Bin));
+to_hex([H|T]) ->
+    [to_digit(H div 16), to_digit(H rem 16) | to_hex(T)].
+
+to_digit(N) when N < 10 -> $0 + N;
+to_digit(N)             -> $a + N-10.
+
+
+parse_term(Bin) when is_binary(Bin) ->
+    parse_term(binary_to_list(Bin));
+parse_term(List) ->
+    {ok, Tokens, _} = erl_scan:string(List ++ "."),
+    erl_parse:parse_term(Tokens).
+
+get_value(Key, List) ->
+    get_value(Key, List, undefined).
+
+get_value(Key, List, Default) ->
+    case lists:keysearch(Key, 1, List) of
+    {value, {Key,Value}} ->
+        Value;
+    false ->
+        Default
+    end.
+
+get_nested_json_value({Props}, [Key|Keys]) ->
+    case couch_util:get_value(Key, Props, nil) of
+    nil -> throw({not_found, <<"missing json key: ", Key/binary>>});
+    Value -> get_nested_json_value(Value, Keys)
+    end;
+get_nested_json_value(Value, []) ->
+    Value;
+get_nested_json_value(_NotJSONObj, _) ->
+    throw({not_found, json_mismatch}).
+
+proplist_apply_field(H, L) ->
+    {R} = json_apply_field(H, {L}),
+    R.
+
+json_apply_field(H, {L}) ->
+    json_apply_field(H, L, []).
+json_apply_field({Key, NewValue}, [{Key, _OldVal} | Headers], Acc) ->
+    json_apply_field({Key, NewValue}, Headers, Acc);
+json_apply_field({Key, NewValue}, [{OtherKey, OtherVal} | Headers], Acc) ->
+    json_apply_field({Key, NewValue}, Headers, [{OtherKey, OtherVal} | Acc]);
+json_apply_field({Key, NewValue}, [], Acc) ->
+    {[{Key, NewValue}|Acc]}.
+
+json_user_ctx(#db{name=DbName, user_ctx=Ctx}) ->
+    {[{<<"db">>, DbName},
+            {<<"name">>,Ctx#user_ctx.name},
+            {<<"roles">>,Ctx#user_ctx.roles}]}.
+
+json_decode(D) ->
+    try
+        jiffy:decode(D)
+    catch
+        throw:Error ->
+            throw({invalid_json, Error})
+    end.
+
+% returns a random integer
+rand32() ->
+    crypto:rand_uniform(0, 16#100000000).
+
+% given a pathname "../foo/bar/" it gives back the fully qualified
+% absolute pathname.
+abs_pathname(" " ++ Filename) ->
+    % strip leading whitspace
+    abs_pathname(Filename);
+abs_pathname([$/ |_]=Filename) ->
+    Filename;
+abs_pathname(Filename) ->
+    {ok, Cwd} = file:get_cwd(),
+    {Filename2, Args} = separate_cmd_args(Filename, ""),
+    abs_pathname(Filename2, Cwd) ++ Args.
+
+abs_pathname(Filename, Dir) ->
+    Name = filename:absname(Filename, Dir ++ "/"),
+    OutFilename = filename:join(fix_path_list(filename:split(Name), [])),
+    % If the filename is a dir (last char slash, put back end slash
+    case string:right(Filename,1) of
+    "/" ->
+        OutFilename ++ "/";
+    "\\" ->
+        OutFilename ++ "/";
+    _Else->
+        OutFilename
+    end.
+
+% if this as an executable with arguments, seperate out the arguments
+% ""./foo\ bar.sh -baz=blah" -> {"./foo\ bar.sh", " -baz=blah"}
+separate_cmd_args("", CmdAcc) ->
+    {lists:reverse(CmdAcc), ""};
+separate_cmd_args("\\ " ++ Rest, CmdAcc) -> % handle skipped value
+    separate_cmd_args(Rest, " \\" ++ CmdAcc);
+separate_cmd_args(" " ++ Rest, CmdAcc) ->
+    {lists:reverse(CmdAcc), " " ++ Rest};
+separate_cmd_args([Char|Rest], CmdAcc) ->
+    separate_cmd_args(Rest, [Char | CmdAcc]).
+
+% Is a character whitespace?
+is_whitespace($\s) -> true;
+is_whitespace($\t) -> true;
+is_whitespace($\n) -> true;
+is_whitespace($\r) -> true;
+is_whitespace(_Else) -> false.
+
+
+% removes leading and trailing whitespace from a string
+trim(String) ->
+    String2 = lists:dropwhile(fun is_whitespace/1, String),
+    lists:reverse(lists:dropwhile(fun is_whitespace/1, lists:reverse(String2))).
+
+% takes a heirarchical list of dirs and removes the dots ".", double dots
+% ".." and the corresponding parent dirs.
+fix_path_list([], Acc) ->
+    lists:reverse(Acc);
+fix_path_list([".."|Rest], [_PrevAcc|RestAcc]) ->
+    fix_path_list(Rest, RestAcc);
+fix_path_list(["."|Rest], Acc) ->
+    fix_path_list(Rest, Acc);
+fix_path_list([Dir | Rest], Acc) ->
+    fix_path_list(Rest, [Dir | Acc]).
+
+
+implode(List, Sep) ->
+    implode(List, Sep, []).
+
+implode([], _Sep, Acc) ->
+    lists:flatten(lists:reverse(Acc));
+implode([H], Sep, Acc) ->
+    implode([], Sep, [H|Acc]);
+implode([H|T], Sep, Acc) ->
+    implode(T, Sep, [Sep,H|Acc]).
+
+should_flush() ->
+    should_flush(?FLUSH_MAX_MEM).
+
+should_flush(MemThreshHold) ->
+    {memory, ProcMem} = process_info(self(), memory),
+    BinMem = lists:foldl(fun({_Id, Size, _NRefs}, Acc) -> Size+Acc end,
+        0, element(2,process_info(self(), binary))),
+    if ProcMem+BinMem > 2*MemThreshHold ->
+        garbage_collect(),
+        {memory, ProcMem2} = process_info(self(), memory),
+        BinMem2 = lists:foldl(fun({_Id, Size, _NRefs}, Acc) -> Size+Acc end,
+            0, element(2,process_info(self(), binary))),
+        ProcMem2+BinMem2 > MemThreshHold;
+    true -> false end.
+
+encodeBase64Url(Url) ->
+    Url1 = re:replace(base64:encode(Url), ["=+", $$], ""),
+    Url2 = re:replace(Url1, "/", "_", [global]),
+    re:replace(Url2, "\\+", "-", [global, {return, binary}]).
+
+decodeBase64Url(Url64) ->
+    Url1 = re:replace(Url64, "-", "+", [global]),
+    Url2 = re:replace(Url1, "_", "/", [global]),
+    Padding = lists:duplicate((4 - iolist_size(Url2) rem 4) rem 4, $=),
+    base64:decode(iolist_to_binary([Url2, Padding])).
+
+dict_find(Key, Dict, DefaultValue) ->
+    case dict:find(Key, Dict) of
+    {ok, Value} ->
+        Value;
+    error ->
+        DefaultValue
+    end.
+
+to_binary(V) when is_binary(V) ->
+    V;
+to_binary(V) when is_list(V) ->
+    try
+        list_to_binary(V)
+    catch
+        _:_ ->
+            list_to_binary(io_lib:format("~p", [V]))
+    end;
+to_binary(V) when is_atom(V) ->
+    list_to_binary(atom_to_list(V));
+to_binary(V) ->
+    list_to_binary(io_lib:format("~p", [V])).
+
+to_integer(V) when is_integer(V) ->
+    V;
+to_integer(V) when is_list(V) ->
+    erlang:list_to_integer(V);
+to_integer(V) when is_binary(V) ->
+    erlang:list_to_integer(binary_to_list(V)).
+
+to_list(V) when is_list(V) ->
+    V;
+to_list(V) when is_binary(V) ->
+    binary_to_list(V);
+to_list(V) when is_atom(V) ->
+    atom_to_list(V);
+to_list(V) ->
+    lists:flatten(io_lib:format("~p", [V])).
+
+url_encode(Bin) when is_binary(Bin) ->
+    url_encode(binary_to_list(Bin));
+url_encode([H|T]) ->
+    if
+    H >= $a, $z >= H ->
+        [H|url_encode(T)];
+    H >= $A, $Z >= H ->
+        [H|url_encode(T)];
+    H >= $0, $9 >= H ->
+        [H|url_encode(T)];
+    H == $_; H == $.; H == $-; H == $: ->
+        [H|url_encode(T)];
+    true ->
+        case lists:flatten(io_lib:format("~.16.0B", [H])) of
+        [X, Y] ->
+            [$%, X, Y | url_encode(T)];
+        [X] ->
+            [$%, $0, X | url_encode(T)]
+        end
+    end;
+url_encode([]) ->
+    [].
+
+verify([X|RestX], [Y|RestY], Result) ->
+    verify(RestX, RestY, (X bxor Y) bor Result);
+verify([], [], Result) ->
+    Result == 0.
+
+verify(<<X/binary>>, <<Y/binary>>) ->
+    verify(?b2l(X), ?b2l(Y));
+verify(X, Y) when is_list(X) and is_list(Y) ->
+    case length(X) == length(Y) of
+        true ->
+            verify(X, Y, 0);
+        false ->
+            false
+    end;
+verify(_X, _Y) -> false.
+
+-spec md5(Data::(iolist() | binary())) -> Digest::binary().
+md5(Data) ->
+    try crypto:md5(Data) catch error:_ -> erlang:md5(Data) end.
+
+-spec md5_init() -> Context::binary().
+md5_init() ->
+    try crypto:md5_init() catch error:_ -> erlang:md5_init() end.
+
+-spec md5_update(Context::binary(), Data::(iolist() | binary())) ->
+    NewContext::binary().
+md5_update(Ctx, D) ->
+    try crypto:md5_update(Ctx,D) catch error:_ -> erlang:md5_update(Ctx,D) end.
+
+-spec md5_final(Context::binary()) -> Digest::binary().
+md5_final(Ctx) ->
+    try crypto:md5_final(Ctx) catch error:_ -> erlang:md5_final(Ctx) end.
+
+% linear search is faster for small lists, length() is 0.5 ms for 100k list
+reorder_results(Keys, SortedResults) when length(Keys) < 100 ->
+    [couch_util:get_value(Key, SortedResults) || Key <- Keys];
+reorder_results(Keys, SortedResults) ->
+    KeyDict = dict:from_list(SortedResults),
+    [dict:fetch(Key, KeyDict) || Key <- Keys].
+
+url_strip_password(Url) ->
+    re:replace(Url,
+        "http(s)?://([^:]+):[^@]+@(.*)$",
+        "http\\1://\\2:*****@\\3",
+        [{return, list}]).
+
+encode_doc_id(#doc{id = Id}) ->
+    encode_doc_id(Id);
+encode_doc_id(Id) when is_list(Id) ->
+    encode_doc_id(?l2b(Id));
+encode_doc_id(<<"_design/", Rest/binary>>) ->
+    "_design/" ++ url_encode(Rest);
+encode_doc_id(<<"_local/", Rest/binary>>) ->
+    "_local/" ++ url_encode(Rest);
+encode_doc_id(Id) ->
+    url_encode(Id).
+
+
+with_db(Db, Fun) when is_record(Db, db) ->
+    Fun(Db);
+with_db(DbName, Fun) ->
+    case couch_db:open_int(DbName, [{user_ctx, #user_ctx{roles=[<<"_admin">>]}}]) of
+        {ok, Db} ->
+            try
+                Fun(Db)
+            after
+                catch couch_db:close(Db)
+            end;
+        Else ->
+            throw(Else)
+    end.
+
+rfc1123_date() ->
+    {{YYYY,MM,DD},{Hour,Min,Sec}} = calendar:universal_time(),
+    DayNumber = calendar:day_of_the_week({YYYY,MM,DD}),
+    lists:flatten(
+      io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT",
+            [day(DayNumber),DD,month(MM),YYYY,Hour,Min,Sec])).
+
+rfc1123_date(undefined) ->
+    undefined;
+rfc1123_date(UniversalTime) ->
+    {{YYYY,MM,DD},{Hour,Min,Sec}} = UniversalTime,
+    DayNumber = calendar:day_of_the_week({YYYY,MM,DD}),
+    lists:flatten(
+      io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT",
+            [day(DayNumber),DD,month(MM),YYYY,Hour,Min,Sec])).
+
+%% day
+
+day(1) -> "Mon";
+day(2) -> "Tue";
+day(3) -> "Wed";
+day(4) -> "Thu";
+day(5) -> "Fri";
+day(6) -> "Sat";
+day(7) -> "Sun".
+
+%% month
+
+month(1) -> "Jan";
+month(2) -> "Feb";
+month(3) -> "Mar";
+month(4) -> "Apr";
+month(5) -> "May";
+month(6) -> "Jun";
+month(7) -> "Jul";
+month(8) -> "Aug";
+month(9) -> "Sep";
+month(10) -> "Oct";
+month(11) -> "Nov";
+month(12) -> "Dec".

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch/src/couch_uuids.erl
----------------------------------------------------------------------
diff --git a/apps/couch/src/couch_uuids.erl b/apps/couch/src/couch_uuids.erl
new file mode 100644
index 0000000..6ed75a1
--- /dev/null
+++ b/apps/couch/src/couch_uuids.erl
@@ -0,0 +1,103 @@
+% 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.
+-module(couch_uuids).
+-include("couch_db.hrl").
+
+-behaviour(gen_server).
+
+-export([start/0, stop/0]).
+-export([new/0, random/0, utc_random/0]).
+
+-export([init/1, terminate/2, code_change/3]).
+-export([handle_call/3, handle_cast/2, handle_info/2]).
+
+start() ->
+    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+stop() ->
+    gen_server:cast(?MODULE, stop).
+
+new() ->
+    gen_server:call(?MODULE, create).
+
+random() ->
+    list_to_binary(couch_util:to_hex(crypto:rand_bytes(16))).
+
+utc_random() ->
+    utc_suffix(couch_util:to_hex(crypto:rand_bytes(9))).
+
+utc_suffix(Suffix) ->
+    Now = {_, _, Micro} = now(),
+    Nowish = calendar:now_to_universal_time(Now),
+    Nowsecs = calendar:datetime_to_gregorian_seconds(Nowish),
+    Then = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
+    Prefix = io_lib:format("~14.16.0b", [(Nowsecs - Then) * 1000000 + Micro]),
+    list_to_binary(Prefix ++ Suffix).
+
+init([]) ->
+    ok = couch_config:register(
+        fun("uuids", _) -> gen_server:cast(?MODULE, change) end
+    ),
+    {ok, state()}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+handle_call(create, _From, random) ->
+    {reply, random(), random};
+handle_call(create, _From, utc_random) ->
+    {reply, utc_random(), utc_random};
+handle_call(create, _From, {utc_id, UtcIdSuffix}) ->
+    {reply, utc_suffix(UtcIdSuffix), {utc_id, UtcIdSuffix}};
+handle_call(create, _From, {sequential, Pref, Seq}) ->
+    Result = ?l2b(Pref ++ io_lib:format("~6.16.0b", [Seq])),
+    case Seq >= 16#fff000 of
+        true ->
+            {reply, Result, {sequential, new_prefix(), inc()}};
+        _ ->
+            {reply, Result, {sequential, Pref, Seq + inc()}}
+    end.
+
+handle_cast(change, _State) ->
+    {noreply, state()};
+handle_cast(stop, State) ->
+    {stop, normal, State};
+handle_cast(_Msg, State) ->
+    {noreply, State}.
+
+handle_info(_Info, State) ->
+    {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
+
+new_prefix() ->
+    couch_util:to_hex((crypto:rand_bytes(13))).
+
+inc() ->
+    crypto:rand_uniform(1, 16#ffe).
+
+state() ->
+    AlgoStr = couch_config:get("uuids", "algorithm", "random"),
+    case couch_util:to_existing_atom(AlgoStr) of
+        random ->
+            random;
+        utc_random ->
+            utc_random;
+        utc_id ->
+            UtcIdSuffix = couch_config:get("uuids", "utc_id_suffix", ""),
+            {utc_id, UtcIdSuffix};
+        sequential ->
+            {sequential, new_prefix(), inc()};
+        Unknown ->
+            throw({unknown_uuid_algorithm, Unknown})
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch/src/couch_work_queue.erl
----------------------------------------------------------------------
diff --git a/apps/couch/src/couch_work_queue.erl b/apps/couch/src/couch_work_queue.erl
new file mode 100644
index 0000000..22968d7
--- /dev/null
+++ b/apps/couch/src/couch_work_queue.erl
@@ -0,0 +1,187 @@
+% 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.
+
+-module(couch_work_queue).
+-behaviour(gen_server).
+
+-include("couch_db.hrl").
+
+% public API
+-export([new/1, queue/2, dequeue/1, dequeue/2, close/1, item_count/1, size/1]).
+
+% gen_server callbacks
+-export([init/1, terminate/2]).
+-export([handle_call/3, handle_cast/2, code_change/3, handle_info/2]).
+
+-record(q, {
+    queue = queue:new(),
+    blocked = [],
+    max_size,
+    max_items,
+    items = 0,
+    size = 0,
+    work_waiters = [],
+    close_on_dequeue = false,
+    multi_workers = false
+}).
+
+
+new(Options) ->
+    gen_server:start_link(couch_work_queue, Options, []).
+
+
+queue(Wq, Item) when is_binary(Item) ->
+    gen_server:call(Wq, {queue, Item, byte_size(Item)}, infinity);
+queue(Wq, Item) ->
+    gen_server:call(Wq, {queue, Item, ?term_size(Item)}, infinity).
+
+
+dequeue(Wq) ->
+    dequeue(Wq, all).
+
+    
+dequeue(Wq, MaxItems) ->
+    try
+        gen_server:call(Wq, {dequeue, MaxItems}, infinity)
+    catch
+        _:_ -> closed
+    end.
+
+
+item_count(Wq) ->
+    try
+        gen_server:call(Wq, item_count, infinity)
+    catch
+        _:_ -> closed
+    end.
+
+
+size(Wq) ->
+    try
+        gen_server:call(Wq, size, infinity)
+    catch
+        _:_ -> closed
+    end.
+
+
+close(Wq) ->
+    gen_server:cast(Wq, close).
+    
+
+init(Options) ->
+    Q = #q{
+        max_size = couch_util:get_value(max_size, Options, nil),
+        max_items = couch_util:get_value(max_items, Options, nil),
+        multi_workers = couch_util:get_value(multi_workers, Options, false)
+    },
+    {ok, Q}.
+
+
+terminate(_Reason, #q{work_waiters=Workers}) ->
+    lists:foreach(fun({W, _}) -> gen_server:reply(W, closed) end, Workers).
+
+    
+handle_call({queue, Item, Size}, From, #q{work_waiters = []} = Q0) ->
+    Q = Q0#q{size = Q0#q.size + Size,
+                items = Q0#q.items + 1,
+                queue = queue:in({Item, Size}, Q0#q.queue)},
+    case (Q#q.size >= Q#q.max_size) orelse
+            (Q#q.items >= Q#q.max_items) of
+    true ->
+        {noreply, Q#q{blocked = [From | Q#q.blocked]}};
+    false ->
+        {reply, ok, Q}
+    end;
+
+handle_call({queue, Item, _}, _From, #q{work_waiters = [{W, _Max} | Rest]} = Q) ->
+    gen_server:reply(W, {ok, [Item]}),
+    {reply, ok, Q#q{work_waiters = Rest}};
+
+handle_call({dequeue, Max}, From, Q) ->
+    #q{work_waiters = Workers, multi_workers = Multi, items = Count} = Q,
+    case {Workers, Multi} of
+    {[_ | _], false} ->
+        exit("Only one caller allowed to wait for this work at a time");
+    {[_ | _], true} ->
+        {noreply, Q#q{work_waiters=Workers ++ [{From, Max}]}};
+    _ ->
+        case Count of
+        0 ->
+            {noreply, Q#q{work_waiters=Workers ++ [{From, Max}]}};
+        C when C > 0 ->
+            deliver_queue_items(Max, Q)
+        end
+    end;
+
+handle_call(item_count, _From, Q) ->
+    {reply, Q#q.items, Q};
+
+handle_call(size, _From, Q) ->
+    {reply, Q#q.size, Q}.
+
+
+deliver_queue_items(Max, Q) ->
+    #q{
+        queue = Queue,
+        items = Count,
+        size = Size,
+        close_on_dequeue = Close,
+        blocked = Blocked
+    } = Q,
+    case (Max =:= all) orelse (Max >= Count) of
+    false ->
+        {Items, Size2, Queue2, Blocked2} = dequeue_items(
+            Max, Size, Queue, Blocked, []),
+        Q2 = Q#q{
+            items = Count - Max, size = Size2, blocked = Blocked2, queue = Queue2
+        },
+        {reply, {ok, Items}, Q2};
+    true ->
+        lists:foreach(fun(F) -> gen_server:reply(F, ok) end, Blocked),
+        Q2 = Q#q{items = 0, size = 0, blocked = [], queue = queue:new()},
+        Items = [Item || {Item, _} <- queue:to_list(Queue)],
+        case Close of
+        false ->
+            {reply, {ok, Items}, Q2};
+        true ->
+            {stop, normal, {ok, Items}, Q2}
+        end
+    end.
+
+
+dequeue_items(0, Size, Queue, Blocked, DequeuedAcc) ->
+    {lists:reverse(DequeuedAcc), Size, Queue, Blocked};
+
+dequeue_items(NumItems, Size, Queue, Blocked, DequeuedAcc) ->
+    {{value, {Item, ItemSize}}, Queue2} = queue:out(Queue),
+    case Blocked of
+    [] ->
+        Blocked2 = Blocked;
+    [From | Blocked2] ->
+        gen_server:reply(From, ok)
+    end,
+    dequeue_items(
+        NumItems - 1, Size - ItemSize, Queue2, Blocked2, [Item | DequeuedAcc]).
+    
+
+handle_cast(close, #q{items = 0} = Q) ->
+    {stop, normal, Q};
+
+handle_cast(close, Q) ->
+    {noreply, Q#q{close_on_dequeue = true}}.
+
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
+
+handle_info(X, Q) ->
+    {stop, X, Q}.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch/src/json_stream_parse.erl
----------------------------------------------------------------------
diff --git a/apps/couch/src/json_stream_parse.erl b/apps/couch/src/json_stream_parse.erl
new file mode 100644
index 0000000..b63e011
--- /dev/null
+++ b/apps/couch/src/json_stream_parse.erl
@@ -0,0 +1,432 @@
+% 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.
+
+-module(json_stream_parse).
+
+
+-export([events/2, to_ejson/1, collect_object/2]).
+
+-define(IS_WS(X), (X == $\  orelse X == $\t orelse X == $\n orelse X == $\r)).
+-define(IS_DELIM(X), (X == $} orelse X == $] orelse X == $,)).
+-define(IS_DIGIT(X), (X >= $0 andalso X =< $9)).
+
+
+
+% Parses the json into events.
+%
+% The DataFun param is a function that produces the data for parsing. When
+% called it must yield a tuple, or the atom done. The first element in the
+% tuple is the data itself, and the second element is a function to be called
+% next to get the next chunk of data in the stream.
+%
+% The EventFun is called everytime a json element is parsed. It must produce
+% a new function to be called for the next event.
+%
+% Events happen each time a new element in the json string is parsed.
+% For simple value types, the data itself is returned:
+% Strings
+% Integers
+% Floats
+% true
+% false
+% null
+%
+% For arrays, the start of the array is signaled by the event array_start
+% atom. The end is signaled by array_end. The events before the end are the
+% values, or nested values.
+%
+% For objects, the start of the object is signaled by the event object_start
+% atom. The end is signaled by object_end. Each key is signaled by
+% {key, KeyString}, and the following event is the value, or start of the
+% value (array_start, object_start).
+%
+events(Data,EventFun) when is_list(Data)->
+    events(list_to_binary(Data),EventFun);
+events(Data,EventFun) when is_binary(Data)->
+    events(fun() -> {Data, fun() -> done end} end,EventFun);
+events(DataFun,EventFun) ->
+    parse_one(DataFun, EventFun, <<>>).
+
+% converts the JSON directly to the erlang represention of Json
+to_ejson(DF) ->
+    {_DF2, EF, _Rest} = events(DF, fun(Ev) -> collect_events(Ev, []) end),
+    [[EJson]] = make_ejson(EF(get_results), [[]]),
+    EJson.
+
+
+% This function is used to return complete objects while parsing streams.
+%
+% Return this function from inside an event function right after getting an
+% object_start event. It then collects the remaining events for that object
+% and converts it to the erlang represention of Json.
+%
+% It then calls your ReturnControl function with the erlang object. Your
+% return control function then should yield another event function.
+%
+% This example stream parses an array of objects, calling
+% fun do_something_with_the_object/1 for each object.
+%
+%    ev_array(array_start) ->
+%        fun(Ev) -> ev_object_loop(Ev) end.
+%
+%    ev_object_loop(object_start) ->
+%        fun(Ev) ->
+%            json_stream_parse:collect_object(Ev,
+%                fun(Obj) ->
+%                    do_something_with_the_object(Obj),
+%                    fun(Ev2) -> ev_object_loop(Ev2) end
+%                end)
+%        end;
+%    ev_object_loop(array_end) ->
+%        ok
+%    end.
+%
+%    % invoke the parse
+%    main() ->
+%        ...
+%        events(Data, fun(Ev) -> ev_array(Ev) end).
+
+collect_object(Ev, ReturnControl) ->
+    collect_object(Ev, 0, ReturnControl, [object_start]).
+
+
+
+% internal methods
+
+parse_one(DF,EF,Acc) ->
+    case toke(DF, Acc) of
+    none ->
+        none;
+    {Token, DF2, Rest} ->
+        case Token of
+        "{" ->
+            EF2 = EF(object_start),
+            {DF3, EF3, Rest2} = parse_object(DF2, EF2, Rest),
+            {DF3, EF3(object_end), Rest2};
+        "[" ->
+            EF2 = EF(array_start),
+            {DF3, EF3, Rest2} = parse_array(DF2, EF2, Rest),
+            {DF3, EF3(array_end), Rest2};
+        Int when is_integer(Int)->
+            {DF2, EF(Int), Rest};
+        Float when is_float(Float)->
+            {DF2, EF(Float), Rest};
+        Atom when is_atom(Atom)->
+            {DF2, EF(Atom), Rest};
+        String when is_binary(String)->
+            {DF2, EF(String), Rest};
+        _OtherToken ->
+            err(unexpected_token)
+        end
+    end.
+
+must_parse_one(DF,EF,Acc,Error)->
+    case parse_one(DF, EF, Acc) of
+    none ->
+        err(Error);
+    Else ->
+        Else
+    end.
+
+must_toke(DF, Data, Error) ->
+    case toke(DF, Data) of
+    none ->
+        err(Error);
+    Result ->
+        Result
+    end.
+
+toke(DF, <<>>) ->
+    case DF() of
+    done ->
+        none;
+    {Data, DF2} ->
+        toke(DF2, Data)
+    end;
+toke(DF, <<C,Rest/binary>>) when ?IS_WS(C)->
+    toke(DF, Rest);
+toke(DF, <<${,Rest/binary>>) ->
+    {"{", DF, Rest};
+toke(DF, <<$},Rest/binary>>) ->
+    {"}", DF, Rest};
+toke(DF, <<$[,Rest/binary>>) ->
+    {"[", DF, Rest};
+toke(DF, <<$],Rest/binary>>) ->
+    {"]", DF, Rest};
+toke(DF, <<$",Rest/binary>>) ->
+    toke_string(DF,Rest,[]);
+toke(DF, <<$,,Rest/binary>>) ->
+    {",", DF, Rest};
+toke(DF, <<$:,Rest/binary>>) ->
+    {":", DF, Rest};
+toke(DF, <<$-,Rest/binary>>) ->
+    {<<C,_/binary>> = Data, DF2} = must_df(DF,1,Rest,expected_number),
+    case ?IS_DIGIT(C) of
+    true ->
+        toke_number_leading(DF2, Data, "-");
+    false ->
+        err(expected_number)
+    end;
+toke(DF, <<C,_/binary>> = Data) when ?IS_DIGIT(C) ->
+    toke_number_leading(DF, Data, []);
+toke(DF, <<$t,Rest/binary>>) ->
+    {Data, DF2} = must_match(<<"rue">>, DF, Rest),
+    {true, DF2, Data};
+toke(DF, <<$f,Rest/binary>>) ->
+    {Data, DF2} = must_match(<<"alse">>, DF, Rest),
+    {false, DF2, Data};
+toke(DF, <<$n,Rest/binary>>) ->
+    {Data, DF2} = must_match(<<"ull">>, DF, Rest),
+    {null, DF2, Data};
+toke(_, _) ->
+    err(bad_token).
+
+
+must_match(Pattern, DF, Data) ->
+    Size = size(Pattern),
+    case must_df(DF, Size, Data, bad_token) of
+    {<<Pattern:Size/binary,Data2/binary>>, DF2} ->
+        {Data2, DF2};
+    {_, _} ->
+        err(bad_token)
+    end.
+
+must_df(DF,Error)->
+    case DF() of
+    done ->
+        err(Error);
+    {Data, DF2} ->
+        {Data, DF2}
+    end.
+
+
+must_df(DF,NeedLen,Acc,Error)->
+    if size(Acc) >= NeedLen ->
+        {Acc, DF};
+    true ->
+        case DF() of
+        done ->
+            err(Error);
+        {Data, DF2} ->
+            must_df(DF2, NeedLen, <<Acc/binary, Data/binary>>, Error)
+        end
+    end.
+
+
+parse_object(DF,EF,Acc) ->
+    case must_toke(DF, Acc, unterminated_object) of
+    {String, DF2, Rest} when is_binary(String)->
+        EF2 = EF({key,String}),
+        case must_toke(DF2,Rest,unterminated_object) of
+        {":", DF3, Rest2} ->
+            {DF4, EF3, Rest3} = must_parse_one(DF3, EF2, Rest2, expected_value),
+            case must_toke(DF4,Rest3, unterminated_object) of
+            {",", DF5, Rest4} ->
+                parse_object(DF5, EF3, Rest4);
+            {"}", DF5, Rest4} ->
+                {DF5, EF3, Rest4};
+            {_, _, _} ->
+                err(unexpected_token)
+            end;
+        _Else ->
+            err(expected_colon)
+        end;
+    {"}", DF2, Rest} ->
+        {DF2, EF, Rest};
+    {_, _, _} ->
+        err(unexpected_token)
+    end.
+
+parse_array0(DF,EF,Acc) ->
+    case toke(DF, Acc) of
+    none ->
+        err(unterminated_array);
+    {",", DF2, Rest} ->
+        parse_array(DF2,EF,Rest);
+    {"]", DF2, Rest} ->
+        {DF2,EF,Rest};
+    _ ->
+        err(unexpected_token)
+    end.
+
+parse_array(DF,EF,Acc) ->
+    case toke(DF, Acc) of
+    none ->
+         err(unterminated_array);
+    {Token, DF2, Rest} ->
+        case Token of
+        "{" ->
+            EF2 = EF(object_start),
+            {DF3, EF3, Rest2} = parse_object(DF2, EF2, Rest),
+            parse_array0(DF3, EF3(object_end), Rest2);
+        "[" ->
+            EF2 = EF(array_start),
+            {DF3, EF3, Rest2} = parse_array(DF2, EF2, Rest),
+            parse_array0(DF3, EF3(array_end), Rest2);
+        Int when is_integer(Int)->
+            parse_array0(DF2, EF(Int), Rest);
+        Float when is_float(Float)->
+            parse_array0(DF2, EF(Float), Rest);
+        Atom when is_atom(Atom)->
+            parse_array0(DF2, EF(Atom), Rest);
+        String when is_binary(String)->
+            parse_array0(DF2, EF(String), Rest);
+        "]" ->
+            {DF2, EF, Rest};
+        _ ->
+            err(unexpected_token)
+        end
+    end.
+
+
+toke_string(DF, <<>>, Acc) ->
+    {Data, DF2} = must_df(DF, unterminated_string),
+    toke_string(DF2, Data, Acc);
+toke_string(DF, <<$\\,$",Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$" | Acc]);
+toke_string(DF, <<$\\,$\\,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$\\ | Acc]);
+toke_string(DF, <<$\\,$/,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$/ | Acc]);
+toke_string(DF, <<$\\,$b,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$\b | Acc]);
+toke_string(DF, <<$\\,$f,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$\f | Acc]);
+toke_string(DF, <<$\\,$n,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$\n | Acc]);
+toke_string(DF, <<$\\,$r,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$\r | Acc]);
+toke_string(DF, <<$\\,$t,Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [$\t | Acc]);
+toke_string(DF, <<$\\,$u,Rest/binary>>, Acc) ->
+    {<<A,B,C,D,Data/binary>>, DF2} = must_df(DF,4,Rest,missing_hex),
+    UTFChar = erlang:list_to_integer([A, B, C, D], 16),
+    if UTFChar == 16#FFFF orelse UTFChar == 16#FFFE ->
+        err(invalid_utf_char);
+    true ->
+        ok
+    end,
+    Chars = xmerl_ucs:to_utf8(UTFChar),
+    toke_string(DF2, Data, lists:reverse(Chars) ++ Acc);
+toke_string(DF, <<$\\>>, Acc) ->
+    {Data, DF2} = must_df(DF, unterminated_string),
+    toke_string(DF2, <<$\\,Data/binary>>, Acc);
+toke_string(_DF, <<$\\, _/binary>>, _Acc) ->
+    err(bad_escape);
+toke_string(DF, <<$", Rest/binary>>, Acc) ->
+    {list_to_binary(lists:reverse(Acc)), DF, Rest};
+toke_string(DF, <<C, Rest/binary>>, Acc) ->
+    toke_string(DF, Rest, [C | Acc]).
+
+
+toke_number_leading(DF, <<Digit,Rest/binary>>, Acc)
+        when ?IS_DIGIT(Digit) ->
+    toke_number_leading(DF, Rest, [Digit | Acc]);
+toke_number_leading(DF, <<C,_/binary>>=Rest, Acc)
+        when ?IS_WS(C) orelse ?IS_DELIM(C) ->
+    {list_to_integer(lists:reverse(Acc)), DF, Rest};
+toke_number_leading(DF, <<>>, Acc) ->
+    case DF() of
+    done ->
+         {list_to_integer(lists:reverse(Acc)), fun() -> done end, <<>>};
+    {Data, DF2} ->
+        toke_number_leading(DF2, Data, Acc)
+    end;
+toke_number_leading(DF, <<$., Rest/binary>>, Acc) ->
+    toke_number_trailing(DF, Rest, [$.|Acc]);
+toke_number_leading(DF, <<$e, Rest/binary>>, Acc) ->
+    toke_number_exponent(DF, Rest, [$e, $0, $.|Acc]);
+toke_number_leading(DF, <<$E, Rest/binary>>, Acc) ->
+    toke_number_exponent(DF, Rest, [$e, $0, $.|Acc]);
+toke_number_leading(_, _, _) ->
+    err(unexpected_character_in_number).
+
+toke_number_trailing(DF, <<Digit,Rest/binary>>, Acc)
+        when ?IS_DIGIT(Digit) ->
+    toke_number_trailing(DF, Rest, [Digit | Acc]);
+toke_number_trailing(DF, <<C,_/binary>>=Rest, Acc)
+        when ?IS_WS(C) orelse ?IS_DELIM(C) ->
+    {list_to_float(lists:reverse(Acc)), DF, Rest};
+toke_number_trailing(DF, <<>>, Acc) ->
+    case DF() of
+    done ->
+        {list_to_float(lists:reverse(Acc)), fun() -> done end, <<>>};
+    {Data, DF2} ->
+        toke_number_trailing(DF2, Data, Acc)
+    end;
+toke_number_trailing(DF, <<"e", Rest/binary>>, [C|_]=Acc) when C /= $. ->
+    toke_number_exponent(DF, Rest, [$e|Acc]);
+toke_number_trailing(DF, <<"E", Rest/binary>>, [C|_]=Acc) when C /= $. ->
+    toke_number_exponent(DF, Rest, [$e|Acc]);
+toke_number_trailing(_, _, _) ->
+    err(unexpected_character_in_number).
+
+
+toke_number_exponent(DF, <<Digit,Rest/binary>>, Acc) when ?IS_DIGIT(Digit) ->
+    toke_number_exponent(DF, Rest, [Digit | Acc]);
+toke_number_exponent(DF, <<Sign,Rest/binary>>, [$e|_]=Acc)
+        when Sign == $+ orelse Sign == $- ->
+    toke_number_exponent(DF, Rest, [Sign | Acc]);
+toke_number_exponent(DF, <<C,_/binary>>=Rest, Acc)
+        when ?IS_WS(C) orelse ?IS_DELIM(C) ->
+    {list_to_float(lists:reverse(Acc)), DF, Rest};
+toke_number_exponent(DF, <<>>, Acc) ->
+    case DF() of
+    done ->
+        {list_to_float(lists:reverse(Acc)), fun() -> done end, <<>>};
+    {Data, DF2} ->
+        toke_number_exponent(DF2, Data, Acc)
+    end;
+toke_number_exponent(_, _, _) ->
+        err(unexpected_character_in_number).
+
+
+err(Error)->
+    throw({parse_error,Error}).
+
+
+make_ejson([], Stack) ->
+    Stack;
+make_ejson([array_start | RevEvs], [ArrayValues, PrevValues | RestStack]) ->
+    make_ejson(RevEvs, [[ArrayValues | PrevValues] | RestStack]);
+make_ejson([array_end | RevEvs], Stack) ->
+    make_ejson(RevEvs, [[] | Stack]);
+make_ejson([object_start | RevEvs], [ObjValues, PrevValues | RestStack]) ->
+    make_ejson(RevEvs, [[{ObjValues} | PrevValues] | RestStack]);
+make_ejson([object_end | RevEvs], Stack) ->
+    make_ejson(RevEvs, [[] | Stack]);
+make_ejson([{key, String} | RevEvs], [[PrevValue|RestObject] | RestStack] = _Stack) ->
+    make_ejson(RevEvs, [[{String, PrevValue}|RestObject] | RestStack]);
+make_ejson([Value | RevEvs], [Vals | RestStack] = _Stack) ->
+    make_ejson(RevEvs, [[Value | Vals] | RestStack]).
+
+collect_events(get_results, Acc) ->
+    Acc;
+collect_events(Ev, Acc) ->
+    fun(NextEv) -> collect_events(NextEv, [Ev | Acc]) end.
+
+
+collect_object(object_end, 0, ReturnControl, Acc) ->
+    [[Obj]] = make_ejson([object_end | Acc], [[]]),
+    ReturnControl(Obj);
+collect_object(object_end, NestCount, ReturnControl, Acc) ->
+    fun(Ev) ->
+        collect_object(Ev, NestCount - 1, ReturnControl, [object_end | Acc])
+    end;
+collect_object(object_start, NestCount, ReturnControl, Acc) ->
+    fun(Ev) ->
+        collect_object(Ev, NestCount + 1, ReturnControl, [object_start | Acc])
+    end;
+collect_object(Ev, NestCount, ReturnControl, Acc) ->
+    fun(Ev2) ->
+        collect_object(Ev2, NestCount, ReturnControl, [Ev | Acc])
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/build_icu.sh
----------------------------------------------------------------------
diff --git a/apps/couch_collate/build_icu.sh b/apps/couch_collate/build_icu.sh
new file mode 100755
index 0000000..e6ba834
--- /dev/null
+++ b/apps/couch_collate/build_icu.sh
@@ -0,0 +1,191 @@
+#!/bin/sh
+
+CORE_TOP=`pwd`
+export CORE_TOP
+
+CURLBIN=`which curl`
+if ! test -n "CURLBIN"; then
+    display_error "Error: curl is required. Add it to 'PATH'"
+    exit 1
+fi
+
+GUNZIP=`which gunzip`
+UNZIP=`which unzip`
+TAR=`which tar`
+GNUMAKE=`which gmake 2>/dev/null || which make`
+PATCHES=$CORE_TOP/patches
+STATICLIBS=$CORE_TOP/.libs
+DISTDIR=$CORE_TOP/.dists
+
+# icu sources
+ICU_VER=4.4.2
+ICU_DISTNAME=icu4c-4_4_2-src.tgz
+ICU_SITE=http://dl.refuge.io
+ICUDIR=$STATICLIBS/icu_src/icu
+
+
+[ "$MACHINE" ] || MACHINE=`(uname -m) 2>/dev/null` || MACHINE="unknown"
+[ "$RELEASE" ] || RELEASE=`(uname -r) 2>/dev/null` || RELEASE="unknown"
+[ "$SYSTEM" ] || SYSTEM=`(uname -s) 2>/dev/null`  || SYSTEM="unknown"
+[ "$BUILD" ] || VERSION=`(uname -v) 2>/dev/null` || VERSION="unknown"
+
+
+CFLAGS="-g -O2 -Wall"
+LDFLAGS="-lstdc++"
+ARCH=
+ISA64=
+GNUMAKE=make
+CC=gcc
+CXX=g++
+PATCH=patch
+case "$SYSTEM" in
+    Linux)
+        ARCH=`arch 2>/dev/null`
+        ;;
+    FreeBSD|OpenBSD|NetBSD)
+        ARCH=`(uname -p) 2>/dev/null`
+        GNUMAKE=gmake
+        ;;
+    Darwin)
+        ARCH=`(uname -p) 2>/dev/null`
+        ISA64=`(sysctl -n hw.optional.x86_64) 2>/dev/null`
+        ;;
+    Solaris)
+        ARCH=`(uname -p) 2>/dev/null`
+        GNUMAKE=gmake
+        PATCH=gpatch
+        ;;
+    *)
+        ARCH="unknown"
+        ;;
+esac
+
+
+# TODO: add mirror & signature validation support
+fetch()
+{
+    TARGET=$DISTDIR/$1
+    if ! test -f $TARGET; then
+        echo "==> Fetch $1 to $TARGET"
+        $CURLBIN --progress-bar -L $2/$1 -o $TARGET
+    fi
+}
+
+build_icu()
+{
+    fetch $ICU_DISTNAME $ICU_SITE
+
+    mkdir -p $ICUDIR
+
+    echo "==> icu (compile)"
+
+    rm -rf $STATICLIBS/icu*
+
+    cd $STATICLIBS
+    $GUNZIP -c $DISTDIR/$ICU_DISTNAME | $TAR xf - -C $STATICLIBS/icu_src
+
+    # apply patches
+    cd $STATICLIBS/icu_src
+    for P in $PATCHES/icu/*.patch; do \
+        (patch -p0 -i $P || echo "skipping patch"); \
+    done
+
+    cd $ICUDIR/source
+
+    CFLAGS="-g -Wall -fPIC -Os"
+
+    env CC="gcc" CXX="g++" CPPFLAGS="" LDFLAGS="-fPIC" \
+	CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" \
+        ./configure --disable-debug \
+		    --enable-static \
+		    --disable-shared \
+		    --disable-icuio \
+		    --disable-layout \
+		    --disable-extras \
+		    --disable-tests \
+		    --disable-samples \
+		    --prefix=$STATICLIBS/icu && \
+        $GNUMAKE && $GNUMAKE install
+}
+
+do_setup()
+{
+    echo "==> build icu"
+    mkdir -p $DISTDIR
+    mkdir -p $STATICLIBS
+}
+
+do_builddeps()
+{
+    if [ ! -f $STATICLIBS/icu/lib/libicui18n.a ]; then
+        build_icu
+    fi
+}
+
+
+clean()
+{
+    rm -rf $STATICLIBS
+    rm -rf $DISTDIR
+}
+
+
+
+usage()
+{
+    cat << EOF
+Usage: $basename [command] [OPTIONS]
+
+The $basename command compile Mozilla Spidermonkey and ICU statically
+for couch_core.
+
+Commands:
+
+    all:        build couch_core static libs
+    clean:      clean static libs
+    -?:         display usage
+
+Report bugs at <https://github.com/refuge/couch_core>.
+EOF
+}
+
+
+if [ ! "x$COUCHDB_STATIC" = "x1" ]; then
+    exit 0
+fi
+
+if [ ! "x$USE_STATIC_ICU" = "x1" ]; then
+    exit 0
+fi
+
+if [ "x$1" = "x" ]; then
+    do_setup
+    do_builddeps
+	exit 0
+fi
+
+case "$1" in
+    all)
+        shift 1
+        do_setup
+        do_builddeps
+        ;;
+    clean)
+        shift 1
+        clean
+        ;;
+    help|--help|-h|-?)
+        usage
+        exit 0
+        ;;
+    *)
+        echo $basename: ERROR Unknown command $arg 1>&2
+        echo 1>&2
+        usage 1>&2
+        echo "### $basename: Exitting." 1>&2
+        exit 1;
+        ;;
+esac
+
+
+exit 0

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/c_src/couch_collate.c
----------------------------------------------------------------------
diff --git a/apps/couch_collate/c_src/couch_collate.c b/apps/couch_collate/c_src/couch_collate.c
new file mode 100644
index 0000000..c5453d2
--- /dev/null
+++ b/apps/couch_collate/c_src/couch_collate.c
@@ -0,0 +1,281 @@
+/*
+
+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.
+
+*/
+
+#ifdef DARWIN
+#define U_HIDE_DRAFT_API 1
+#define U_DISABLE_RENAMING 1
+#endif
+
+#include "erl_nif.h"
+#include "unicode/ucol.h"
+#include "unicode/ucasemap.h"
+#include <stdio.h>
+#include <assert.h>
+
+static ERL_NIF_TERM ATOM_TRUE;
+static ERL_NIF_TERM ATOM_FALSE;
+static ERL_NIF_TERM ATOM_NULL;
+
+typedef struct {
+    ErlNifEnv* env;
+    int error;
+    UCollator* coll;
+} ctx_t;
+
+typedef struct {
+    UCollator** collators;
+    int collStackTop;
+    int numCollators;
+    ErlNifMutex* collMutex;
+} priv_data_t;
+
+static ERL_NIF_TERM collate_nif(ErlNifEnv*, int, const ERL_NIF_TERM []);
+static int collate_binary(priv_data_t*, ctx_t*, ERL_NIF_TERM, ERL_NIF_TERM, ERL_NIF_TERM);
+static int on_load(ErlNifEnv*, void**, ERL_NIF_TERM);
+static void on_unload(ErlNifEnv*, void*);
+static __inline void reserve_coll(priv_data_t*, ctx_t*);
+static __inline void release_coll(priv_data_t*, ctx_t*);
+int on_reload(ErlNifEnv*, void**, ERL_NIF_TERM);
+int on_upgrade(ErlNifEnv*, void**, void**, ERL_NIF_TERM);
+
+void
+reserve_coll(priv_data_t* pData, ctx_t *ctx)
+{
+    if (ctx->coll == NULL) {
+        enif_mutex_lock(pData->collMutex);
+        assert(pData->collStackTop < pData->numCollators);
+        ctx->coll = pData->collators[pData->collStackTop];
+        pData->collStackTop += 1;
+        enif_mutex_unlock(pData->collMutex);
+    }
+}
+
+
+void
+release_coll(priv_data_t* pData, ctx_t *ctx)
+{
+    if (ctx->coll != NULL) {
+        enif_mutex_lock(pData->collMutex);
+        pData->collStackTop -= 1;
+        assert(pData->collStackTop >= 0);
+        enif_mutex_unlock(pData->collMutex);
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static ERL_NIF_TERM
+collate_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
+    ERL_NIF_TERM term_a          = argv[0];
+    ERL_NIF_TERM term_b          = argv[1];
+    ERL_NIF_TERM term_has_nocase = argv[2];
+
+    ctx_t ctx;
+    int result;
+    priv_data_t* pData;
+
+    ctx.env = env;
+    ctx.error = 0;
+    ctx.coll = NULL;
+
+    pData = (priv_data_t*) enif_priv_data(env);
+
+    result = collate_binary(pData, &ctx, term_a, term_b, term_has_nocase);
+    release_coll(pData, &ctx);
+
+    return enif_make_int(env, result);
+}
+
+int
+collate_binary(priv_data_t* pData, ctx_t* ctx, ERL_NIF_TERM term_a, ERL_NIF_TERM term_b, ERL_NIF_TERM term_has_nocase)
+{
+    ErlNifBinary binA, binB;
+    int has_nocase, response;
+
+    if(!enif_get_int(ctx->env, term_has_nocase, &has_nocase)) {
+        ctx->error = 1;
+        return 0;
+    }
+    if(!enif_inspect_binary(ctx->env, term_a, &binA)) {
+        ctx->error = 1;
+        return 0;
+    }
+    if(!enif_inspect_binary(ctx->env, term_b, &binB)) {
+        ctx->error = 1;
+        return 0;
+    }
+
+    switch(has_nocase) {
+    case 0: /* COLLATE */
+    case 1: /* COLLATE_NO_CASE: */
+        {
+        UErrorCode status = U_ZERO_ERROR;
+        UCharIterator iterA;
+        UCharIterator iterB;
+
+        uiter_setUTF8(&iterA, (const char *) binA.data, (uint32_t) binA.size);
+        uiter_setUTF8(&iterB, (const char *) binB.data, (uint32_t) binB.size);
+
+        /* grab a collator */
+        reserve_coll(pData, ctx);
+
+        if (has_nocase == 1) /* switching this collator to case insensitive */
+          ucol_setAttribute(ctx->coll, UCOL_STRENGTH, UCOL_PRIMARY, &status);
+
+        /* by default, it will collate case sensitive */
+        response = ucol_strcollIter(ctx->coll, &iterA, &iterB, &status);
+
+        if (has_nocase == 1) /* puting back this collator to case sensitive */
+          ucol_setAttribute(ctx->coll, UCOL_STRENGTH, UCOL_DEFAULT, &status);
+
+        break;
+        }
+
+    default:
+        response = -1;
+    }
+
+    return response;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    priv_data_t* pData = (priv_data_t*)enif_alloc(sizeof(priv_data_t));
+    int i, j;
+
+    /* Initialize the structure */
+    pData->collators = NULL;
+    pData->collStackTop = 0;
+    pData->numCollators = 0;
+    pData->collMutex = NULL;
+
+    if (!enif_get_int(env, info, &(pData->numCollators) )) {
+        enif_free((char*)pData);
+        return 1;
+    }
+
+    if (pData->numCollators < 1) {
+        enif_free((char*)pData);
+        return 2;
+    }
+
+    pData->collMutex = enif_mutex_create((char *)"coll_mutex");
+
+    if (pData->collMutex == NULL) {
+        enif_free((char*)pData);
+        return 3;
+    }
+
+    pData->collators = enif_alloc(sizeof(UCollator*) * pData->numCollators);
+
+    if (pData->collators == NULL) {
+        enif_mutex_destroy(pData->collMutex);
+        enif_free((char*)pData);
+        return 4;
+    }
+
+    for (i = 0; i < pData->numCollators; i++) {
+        pData->collators[i] = ucol_open("", &status);
+
+        if (U_FAILURE(status)) {
+            for (j = 0; j < i; j++) {
+                ucol_close(pData->collators[j]);
+            }
+
+            enif_free(pData->collators);
+            enif_mutex_destroy(pData->collMutex);
+
+            enif_free((char*)pData);
+
+            return 5;
+        }
+    }
+
+    ATOM_TRUE = enif_make_atom(env, "true");
+    ATOM_FALSE = enif_make_atom(env, "false");
+    ATOM_NULL = enif_make_atom(env, "null");
+
+    *priv_data = pData;
+
+    return 0;
+}
+
+
+void
+on_unload(ErlNifEnv* env, void* priv_data)
+{
+    priv_data_t* pData = (priv_data_t*)priv_data;
+    if (pData->collators != NULL) {
+        int i;
+
+        for (i = 0; i < pData->numCollators; i++) {
+            ucol_close(pData->collators[i]);
+        }
+
+        enif_free(pData->collators);
+    }
+
+    if (pData->collMutex != NULL) {
+        enif_mutex_destroy(pData->collMutex);
+    }
+
+    enif_free((char*)pData);
+}
+
+int
+on_reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info)
+{
+    return 0;
+}
+
+int
+on_upgrade(ErlNifEnv* env, void** priv_data, void** old_data, ERL_NIF_TERM info)
+{
+    if (*old_data != NULL) {
+        priv_data_t* pData = (priv_data_t*)old_data;
+
+        if (pData->collators != NULL) {
+            int i;
+
+            for (i = 0; i < pData->numCollators; i++) {
+                ucol_close(pData->collators[i]);
+            }
+
+            enif_free(pData->collators);
+        }
+
+        if (pData->collMutex != NULL) {
+            enif_mutex_destroy(pData->collMutex);
+        }
+
+        enif_free((char*)pData);
+    }
+
+    return on_load(env, priv_data, info);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static ErlNifFunc
+nif_funcs[] =
+{
+    {"collate_nif", 3, collate_nif}
+};
+
+ERL_NIF_INIT(couch_collate, nif_funcs, &on_load, &on_reload, &on_upgrade, &on_unload)

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/patches/icu/common-uloc_c.patch
----------------------------------------------------------------------
diff --git a/apps/couch_collate/patches/icu/common-uloc_c.patch b/apps/couch_collate/patches/icu/common-uloc_c.patch
new file mode 100644
index 0000000..fe60732
--- /dev/null
+++ b/apps/couch_collate/patches/icu/common-uloc_c.patch
@@ -0,0 +1,26 @@
+$FreeBSD: ports/devel/icu/files/patch-common-uloc.c,v 1.1 2011/12/23 14:54:18 crees Exp $
+
+From http://bugs.icu-project.org/trac/ticket/8984
+
+Submitted by: Andrei Lavreniyuk <andy.lavr@gmail.com> (thanks!)
+
+--- icu/source/common/uloc.c
++++ icu/source/common/uloc.c
+@@ -1797,7 +1797,7 @@
+                 int32_t variantLen = _deleteVariant(variant, uprv_min(variantSize, (nameCapacity-len)), variantToCompare, n);
+                 len -= variantLen;
+                 if (variantLen > 0) {
+-                    if (name[len-1] == '_') { /* delete trailing '_' */
++                    if (len > 0 && name[len-1] == '_') { /* delete trailing '_' */
+                         --len;
+                     }
+                     addKeyword = VARIANT_MAP[j].keyword;
+@@ -1805,7 +1805,7 @@
+                     break;
+                 }
+             }
+-            if (name[len-1] == '_') { /* delete trailing '_' */
++            if (len > 0 && len <= nameCapacity && name[len-1] == '_') { /* delete trailing '_' */
+                 --len;
+             }
+         }

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/patches/icu/layout_LookupProcessor_cpp.patch
----------------------------------------------------------------------
diff --git a/apps/couch_collate/patches/icu/layout_LookupProcessor_cpp.patch b/apps/couch_collate/patches/icu/layout_LookupProcessor_cpp.patch
new file mode 100644
index 0000000..304d266
--- /dev/null
+++ b/apps/couch_collate/patches/icu/layout_LookupProcessor_cpp.patch
@@ -0,0 +1,13 @@
+--- icu/source/layout/LookupProcessor.cpp
++++ icu/source/layout/LookupProcessor.cpp
+@@ -201,7 +201,9 @@
+ 
+     if (requiredFeatureIndex != 0xFFFF) {
+         requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag);
+-        featureReferences += SWAPW(featureTable->lookupCount);
++	if (requiredFeatureTable) {
++	        featureReferences += SWAPW(requiredFeatureTable->lookupCount);
++	}
+     }
+ 
+     lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/patches/icu/source_config_Makefile_inc_in.patch
----------------------------------------------------------------------
diff --git a/apps/couch_collate/patches/icu/source_config_Makefile_inc_in.patch b/apps/couch_collate/patches/icu/source_config_Makefile_inc_in.patch
new file mode 100644
index 0000000..89d428e
--- /dev/null
+++ b/apps/couch_collate/patches/icu/source_config_Makefile_inc_in.patch
@@ -0,0 +1,12 @@
+--- icu/source/config/Makefile.inc.in.orig	2011-04-07 17:41:15.000000000 +0200
++++ icu/source/config/Makefile.inc.in	2011-04-07 17:41:40.000000000 +0200
+@@ -44,8 +44,7 @@
+ LIBICU = lib$(ICUPREFIX)
+ 
+ # Static library prefix and file extension
+-STATIC_PREFIX = s
+-LIBSICU = lib$(STATIC_PREFIX)$(ICUPREFIX)
++LIBSICU = lib$(ICUPREFIX)
+ A = a
+ 
+ # Suffix at the end of libraries. Usually empty.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/patches/icu/source_icudefs_mk_in.patch
----------------------------------------------------------------------
diff --git a/apps/couch_collate/patches/icu/source_icudefs_mk_in.patch b/apps/couch_collate/patches/icu/source_icudefs_mk_in.patch
new file mode 100644
index 0000000..a1add5e
--- /dev/null
+++ b/apps/couch_collate/patches/icu/source_icudefs_mk_in.patch
@@ -0,0 +1,19 @@
+--- icu/source/icudefs.mk.in.orig	2011-04-07 17:15:44.000000000 +0200
++++ icu/source/icudefs.mk.in	2011-04-07 17:15:56.000000000 +0200
+@@ -189,14 +189,13 @@
+ 
+ ## If we can't use the shared libraries, use the static libraries
+ ifneq ($(ENABLE_SHARED),YES)
+-STATIC_PREFIX_WHEN_USED = s
++STATIC_PREFIX_WHEN_USED =
+ else
+ STATIC_PREFIX_WHEN_USED = 
+ endif
+ 
+ # Static library prefix and file extension
+-STATIC_PREFIX = s
+-LIBSICU = $(LIBPREFIX)$(STATIC_PREFIX)$(ICUPREFIX)
++LIBSICU = $(LIBPREFIX)$(ICUPREFIX)
+ A = a
+ SOBJ = $(SO)
+ 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/platform/osx/icu/unicode/basictz.h
----------------------------------------------------------------------
diff --git a/apps/couch_collate/platform/osx/icu/unicode/basictz.h b/apps/couch_collate/platform/osx/icu/unicode/basictz.h
new file mode 100644
index 0000000..c616a3e
--- /dev/null
+++ b/apps/couch_collate/platform/osx/icu/unicode/basictz.h
@@ -0,0 +1,210 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, International Business Machines Corporation and         *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*/
+#ifndef BASICTZ_H
+#define BASICTZ_H
+
+/**
+ * \file 
+ * \brief C++ API: ICU TimeZone base class
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/timezone.h"
+#include "unicode/tzrule.h"
+#include "unicode/tztrans.h"
+
+U_NAMESPACE_BEGIN
+
+// forward declarations
+class UVector;
+
+/**
+ * <code>BasicTimeZone</code> is an abstract class extending <code>TimeZone</code>.
+ * This class provides some additional methods to access time zone transitions and rules.
+ * All ICU <code>TimeZone</code> concrete subclasses extend this class.
+ * @stable ICU 4.0
+ */
+class U_I18N_API BasicTimeZone: public TimeZone {
+public:
+    /**
+     * Destructor.
+     * @stable ICU 4.0
+     */
+    virtual ~BasicTimeZone();
+
+    /**
+     * Gets the first time zone transition after the base time.
+     * @param base      The base time.
+     * @param inclusive Whether the base time is inclusive or not.
+     * @param result    Receives the first transition after the base time.
+     * @return  TRUE if the transition is found.
+     * @stable ICU 4.0
+     */
+    virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ = 0;
+
+    /**
+     * Gets the most recent time zone transition before the base time.
+     * @param base      The base time.
+     * @param inclusive Whether the base time is inclusive or not.
+     * @param result    Receives the most recent transition before the base time.
+     * @return  TRUE if the transition is found.
+     * @stable ICU 4.0
+     */
+    virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ = 0;
+
+    /**
+     * Checks if the time zone has equivalent transitions in the time range.
+     * This method returns true when all of transition times, from/to standard
+     * offsets and DST savings used by this time zone match the other in the
+     * time range.
+     * @param tz    The <code>BasicTimeZone</code> object to be compared with.
+     * @param start The start time of the evaluated time range (inclusive)
+     * @param end   The end time of the evaluated time range (inclusive)
+     * @param ignoreDstAmount
+     *              When true, any transitions with only daylight saving amount
+     *              changes will be ignored, except either of them is zero.
+     *              For example, a transition from rawoffset 3:00/dstsavings 1:00
+     *              to rawoffset 2:00/dstsavings 2:00 is excluded from the comparison,
+     *              but a transtion from rawoffset 2:00/dstsavings 1:00 to
+     *              rawoffset 3:00/dstsavings 0:00 is included.
+     * @param ec    Output param to filled in with a success or an error.
+     * @return      true if the other time zone has the equivalent transitions in the
+     *              time range.
+     * @stable ICU 4.0
+     */
+    virtual UBool hasEquivalentTransitions(/*const*/ BasicTimeZone& tz, UDate start, UDate end,
+        UBool ignoreDstAmount, UErrorCode& ec) /*const*/;
+
+    /**
+     * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+     * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+     * <code>InitialTimeZoneRule</code>.  The return value range is 0 or any positive value.
+     * @param status    Receives error status code.
+     * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+     * @stable ICU 4.0
+     */
+    virtual int32_t countTransitionRules(UErrorCode& status) /*const*/ = 0;
+
+    /**
+     * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+     * which represent time transitions for this time zone.  On successful return,
+     * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+     * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+     * instances up to the size specified by trscount.  The results are referencing the
+     * rule instance held by this time zone instance.  Therefore, after this time zone
+     * is destructed, they are no longer available.
+     * @param initial       Receives the initial timezone rule
+     * @param trsrules      Receives the timezone transition rules
+     * @param trscount      On input, specify the size of the array 'transitions' receiving
+     *                      the timezone transition rules.  On output, actual number of
+     *                      rules filled in the array will be set.
+     * @param status        Receives error status code.
+     * @stable ICU 4.0
+     */
+    virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+        const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/ = 0;
+
+    /**
+     * Gets the set of time zone rules valid at the specified time.  Some known external time zone
+     * implementations are not capable to handle historic time zone rule changes.  Also some
+     * implementations can only handle certain type of rule definitions.
+     * If this time zone does not use any daylight saving time within about 1 year from the specified
+     * time, only the <code>InitialTimeZone</code> is returned.  Otherwise, the rule for standard
+     * time and daylight saving time transitions are returned in addition to the
+     * <code>InitialTimeZoneRule</code>.  The standard and daylight saving time transition rules are
+     * represented by <code>AnnualTimeZoneRule</code> with <code>DateTimeRule::DOW</code> for its date
+     * rule and <code>DateTimeRule::WALL_TIME</code> for its time rule.  Because daylight saving time
+     * rule is changing time to time in many time zones and also mapping a transition time rule to
+     * different type is lossy transformation, the set of rules returned by this method may be valid
+     * for short period of time.
+     * The time zone rule objects returned by this method is owned by the caller, so the caller is
+     * responsible for deleting them after use.
+     * @param date      The date used for extracting time zone rules.
+     * @param initial   Receives the <code>InitialTimeZone</code>, always not NULL.
+     * @param std       Receives the <code>AnnualTimeZoneRule</code> for standard time transitions.
+     *                  When this time time zone does not observe daylight saving times around the
+     *                  specified date, NULL is set.
+     * @param dst       Receives the <code>AnnualTimeZoneRule</code> for daylight saving time
+     *                  transitions.  When this time zone does not observer daylight saving times
+     *                  around the specified date, NULL is set.
+     * @param status    Receives error status code.
+     * @stable ICU 4.0
+     */
+    virtual void getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
+        AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) /*const*/;
+
+
+    /**
+     * The time type option bit flags used by getOffsetFromLocal
+     * @internal
+     */
+    enum {
+        kStandard = 0x01,
+        kDaylight = 0x03,
+        kFormer = 0x04,
+        kLatter = 0x0C
+    };
+
+    /**
+     * Get time zone offsets from local wall time.
+     * @internal
+     */
+    virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+        int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
+
+protected:
+
+    /**
+     * The time type option bit masks used by getOffsetFromLocal
+     * @internal
+     */
+    enum {
+        kStdDstMask = kDaylight,
+        kFormerLatterMask = kLatter
+    };
+
+    /**
+     * Default constructor.
+     * @stable ICU 4.0
+     */
+    BasicTimeZone();
+
+    /**
+     * Construct a timezone with a given ID.
+     * @param id a system time zone ID
+     * @stable ICU 4.0
+     */
+    BasicTimeZone(const UnicodeString &id);
+
+    /**
+     * Copy constructor.
+     * @param source the object to be copied.
+     * @stable ICU 4.0
+     */
+    BasicTimeZone(const BasicTimeZone& source);
+
+    /**
+     * Gets the set of TimeZoneRule instances applicable to the specified time and after.
+     * @param start     The start date used for extracting time zone rules
+     * @param initial   Receives the InitialTimeZone, always not NULL
+     * @param transitionRules   Receives the transition rules, could be NULL
+     * @param status    Receives error status code
+     */
+    void getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, UVector*& transitionRules,
+        UErrorCode& status) /*const*/;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // BASICTZ_H
+
+//eof

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e62a4fc1/apps/couch_collate/platform/osx/icu/unicode/brkiter.h
----------------------------------------------------------------------
diff --git a/apps/couch_collate/platform/osx/icu/unicode/brkiter.h b/apps/couch_collate/platform/osx/icu/unicode/brkiter.h
new file mode 100644
index 0000000..7df5f14
--- /dev/null
+++ b/apps/couch_collate/platform/osx/icu/unicode/brkiter.h
@@ -0,0 +1,557 @@
+/*
+********************************************************************************
+*   Copyright (C) 1997-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+********************************************************************************
+*
+* File brkiter.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/18/97    aliu        Added typedef for TextCount.  Made DONE const.
+*   05/07/97    aliu        Fixed DLL declaration.
+*   07/09/97    jfitz       Renamed BreakIterator and interface synced with JDK
+*   08/11/98    helena      Sync-up JDK1.2.
+*   01/13/2000  helena      Added UErrorCode parameter to createXXXInstance methods.
+********************************************************************************
+*/
+
+#ifndef BRKITER_H
+#define BRKITER_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Break Iterator.
+ */
+
+#if UCONFIG_NO_BREAK_ITERATION
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Allow the declaration of APIs with pointers to BreakIterator
+ * even when break iteration is removed from the build.
+ */
+class BreakIterator;
+
+U_NAMESPACE_END
+
+#else
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/chariter.h"
+#include "unicode/locid.h"
+#include "unicode/ubrk.h"
+#include "unicode/strenum.h"
+#include "unicode/utext.h"
+#include "unicode/umisc.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * The BreakIterator class implements methods for finding the location
+ * of boundaries in text. BreakIterator is an abstract base class.
+ * Instances of BreakIterator maintain a current position and scan over
+ * text returning the index of characters where boundaries occur.
+ * <p>
+ * Line boundary analysis determines where a text string can be broken
+ * when line-wrapping. The mechanism correctly handles punctuation and
+ * hyphenated words.
+ * <p>
+ * Sentence boundary analysis allows selection with correct
+ * interpretation of periods within numbers and abbreviations, and
+ * trailing punctuation marks such as quotation marks and parentheses.
+ * <p>
+ * Word boundary analysis is used by search and replace functions, as
+ * well as within text editing applications that allow the user to
+ * select words with a double click. Word selection provides correct
+ * interpretation of punctuation marks within and following
+ * words. Characters that are not part of a word, such as symbols or
+ * punctuation marks, have word-breaks on both sides.
+ * <p>
+ * Character boundary analysis allows users to interact with
+ * characters as they expect to, for example, when moving the cursor
+ * through a text string. Character boundary analysis provides correct
+ * navigation of through character strings, regardless of how the
+ * character is stored.  For example, an accented character might be
+ * stored as a base character and a diacritical mark. What users
+ * consider to be a character can differ between languages.
+ * <p>
+ * The text boundary positions are found according to the rules
+ * described in Unicode Standard Annex #29, Text Boundaries, and
+ * Unicode Standard Annex #14, Line Breaking Properties.  These
+ * are available at http://www.unicode.org/reports/tr14/ and
+ * http://www.unicode.org/reports/tr29/.
+ * <p>
+ * In addition to the C++ API defined in this header file, a
+ * plain C API with equivalent functionality is defined in the
+ * file ubrk.h
+ * <p>
+ * Code snippits illustrating the use of the Break Iterator APIs
+ * are available in the ICU User Guide,
+ * http://icu-project.org/userguide/boundaryAnalysis.html
+ * and in the sample program icu/source/samples/break/break.cpp"
+ *
+ */
+class U_COMMON_API BreakIterator : public UObject {
+public:
+    /**
+     *  destructor
+     *  @stable ICU 2.0
+     */
+    virtual ~BreakIterator();
+
+    /**
+     * Return true if another object is semantically equal to this
+     * one. The other object should be an instance of the same subclass of
+     * BreakIterator. Objects of different subclasses are considered
+     * unequal.
+     * <P>
+     * Return true if this BreakIterator is at the same position in the
+     * same text, and is the same class and type (word, line, etc.) of
+     * BreakIterator, as the argument.  Text is considered the same if
+     * it contains the same characters, it need not be the same
+     * object, and styles are not considered.
+     * @stable ICU 2.0
+     */
+    virtual UBool operator==(const BreakIterator&) const = 0;
+
+    /**
+     * Returns the complement of the result of operator==
+     * @param rhs The BreakIterator to be compared for inequality
+     * @return the complement of the result of operator==
+     * @stable ICU 2.0
+     */
+    UBool operator!=(const BreakIterator& rhs) const { return !operator==(rhs); }
+
+    /**
+     * Return a polymorphic copy of this object.  This is an abstract
+     * method which subclasses implement.
+     * @stable ICU 2.0
+     */
+    virtual BreakIterator* clone(void) const = 0;
+
+    /**
+     * Return a polymorphic class ID for this object. Different subclasses
+     * will return distinct unequal values.
+     * @stable ICU 2.0
+     */
+    virtual UClassID getDynamicClassID(void) const = 0;
+
+    /**
+     * Return a CharacterIterator over the text being analyzed.
+     * @stable ICU 2.0
+     */
+    virtual CharacterIterator& getText(void) const = 0;
+
+
+    /**
+      *  Get a UText for the text being analyzed.
+      *  The returned UText is a shallow clone of the UText used internally
+      *  by the break iterator implementation.  It can safely be used to
+      *  access the text without impacting any break iterator operations,
+      *  but the underlying text itself must not be altered.
+      *
+      * @param fillIn A UText to be filled in.  If NULL, a new UText will be
+      *           allocated to hold the result.
+      * @param status receives any error codes.
+      * @return   The current UText for this break iterator.  If an input
+      *           UText was provided, it will always be returned.
+      * @stable ICU 3.4
+      */
+     virtual UText *getUText(UText *fillIn, UErrorCode &status) const = 0;
+
+    /**
+     * Change the text over which this operates. The text boundary is
+     * reset to the start.
+     * @param text The UnicodeString used to change the text.
+     * @stable ICU 2.0
+     */
+    virtual void  setText(const UnicodeString &text) = 0;
+
+    /**
+     * Reset the break iterator to operate over the text represented by
+     * the UText.  The iterator position is reset to the start.
+     *
+     * This function makes a shallow clone of the supplied UText.  This means
+     * that the caller is free to immediately close or otherwise reuse the
+     * Utext that was passed as a parameter, but that the underlying text itself
+     * must not be altered while being referenced by the break iterator.
+     *
+     * @param text The UText used to change the text.
+     * @param status receives any error codes.
+     * @stable ICU 3.4
+     */
+    virtual void  setText(UText *text, UErrorCode &status) = 0;
+
+    /**
+     * Change the text over which this operates. The text boundary is
+     * reset to the start.
+     * Note that setText(UText *) provides similar functionality to this function,
+     * and is more efficient.
+     * @param it The CharacterIterator used to change the text.
+     * @stable ICU 2.0
+     */
+    virtual void  adoptText(CharacterIterator* it) = 0;
+
+    enum {
+        /**
+         * DONE is returned by previous() and next() after all valid
+         * boundaries have been returned.
+         * @stable ICU 2.0
+         */
+        DONE = (int32_t)-1
+    };
+
+    /**
+     * Return the index of the first character in the text being scanned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t first(void) = 0;
+
+    /**
+     * Return the index immediately BEYOND the last character in the text being scanned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t last(void) = 0;
+
+    /**
+     * Return the boundary preceding the current boundary.
+     * @return The character index of the previous text boundary or DONE if all
+     * boundaries have been returned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t previous(void) = 0;
+
+    /**
+     * Return the boundary following the current boundary.
+     * @return The character index of the next text boundary or DONE if all
+     * boundaries have been returned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t next(void) = 0;
+
+    /**
+     * Return character index of the current interator position within the text.
+     * @return The boundary most recently returned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t current(void) const = 0;
+
+    /**
+     * Return the first boundary following the specified offset.
+     * The value returned is always greater than the offset or
+     * the value BreakIterator.DONE
+     * @param offset the offset to begin scanning.
+     * @return The first boundary after the specified offset.
+     * @stable ICU 2.0
+     */
+    virtual int32_t following(int32_t offset) = 0;
+
+    /**
+     * Return the first boundary preceding the specified offset.
+     * The value returned is always smaller than the offset or
+     * the value BreakIterator.DONE
+     * @param offset the offset to begin scanning.
+     * @return The first boundary before the specified offset.
+     * @stable ICU 2.0
+     */
+    virtual int32_t preceding(int32_t offset) = 0;
+
+    /**
+     * Return true if the specfied position is a boundary position.
+     * As a side effect, the current position of the iterator is set
+     * to the first boundary position at or following the specified offset.
+     * @param offset the offset to check.
+     * @return True if "offset" is a boundary position.
+     * @stable ICU 2.0
+     */
+    virtual UBool isBoundary(int32_t offset) = 0;
+
+    /**
+     * Return the nth boundary from the current boundary
+     * @param n which boundary to return.  A value of 0
+     * does nothing.  Negative values move to previous boundaries
+     * and positive values move to later boundaries.
+     * @return The index of the nth boundary from the current position, or
+     * DONE if there are fewer than |n| boundaries in the specfied direction.
+     * @stable ICU 2.0
+     */
+    virtual int32_t next(int32_t n) = 0;
+
+    /**
+     * Create BreakIterator for word-breaks using the given locale.
+     * Returns an instance of a BreakIterator implementing word breaks.
+     * WordBreak is useful for word selection (ex. double click)
+     * @param where the locale.
+     * @param status the error code
+     * @return A BreakIterator for word-breaks.  The UErrorCode& status
+     * parameter is used to return status information to the user.
+     * To check whether the construction succeeded or not, you should check
+     * the value of U_SUCCESS(err).  If you wish more detailed information, you
+     * can check for informational error results which still indicate success.
+     * U_USING_FALLBACK_WARNING indicates that a fall back locale was used.  For
+     * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+     * used.  U_USING_DEFAULT_WARNING indicates that the default locale data was
+     * used; neither the requested locale nor any of its fall back locales
+     * could be found.
+     * The caller owns the returned object and is responsible for deleting it.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createWordInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for line-breaks using specified locale.
+     * Returns an instance of a BreakIterator implementing line breaks. Line
+     * breaks are logically possible line breaks, actual line breaks are
+     * usually determined based on display width.
+     * LineBreak is useful for word wrapping text.
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for line-breaks.  The UErrorCode& status
+     * parameter is used to return status information to the user.
+     * To check whether the construction succeeded or not, you should check
+     * the value of U_SUCCESS(err).  If you wish more detailed information, you
+     * can check for informational error results which still indicate success.
+     * U_USING_FALLBACK_WARNING indicates that a fall back locale was used.  For
+     * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+     * used.  U_USING_DEFAULT_WARNING indicates that the default locale data was
+     * used; neither the requested locale nor any of its fall back locales
+     * could be found.
+     * The caller owns the returned object and is responsible for deleting it.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createLineInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for character-breaks using specified locale
+     * Returns an instance of a BreakIterator implementing character breaks.
+     * Character breaks are boundaries of combining character sequences.
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for character-breaks.  The UErrorCode& status
+     * parameter is used to return status information to the user.
+     * To check whether the construction succeeded or not, you should check
+     * the value of U_SUCCESS(err).  If you wish more detailed information, you
+     * can check for informational error results which still indicate success.
+     * U_USING_FALLBACK_WARNING indicates that a fall back locale was used.  For
+     * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+     * used.  U_USING_DEFAULT_WARNING indicates that the default locale data was
+     * used; neither the requested locale nor any of its fall back locales
+     * could be found.
+     * The caller owns the returned object and is responsible for deleting it.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createCharacterInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for sentence-breaks using specified locale
+     * Returns an instance of a BreakIterator implementing sentence breaks.
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for sentence-breaks.  The UErrorCode& status
+     * parameter is used to return status information to the user.
+     * To check whether the construction succeeded or not, you should check
+     * the value of U_SUCCESS(err).  If you wish more detailed information, you
+     * can check for informational error results which still indicate success.
+     * U_USING_FALLBACK_WARNING indicates that a fall back locale was used.  For
+     * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+     * used.  U_USING_DEFAULT_WARNING indicates that the default locale data was
+     * used; neither the requested locale nor any of its fall back locales
+     * could be found.
+     * The caller owns the returned object and is responsible for deleting it.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createSentenceInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for title-casing breaks using the specified locale
+     * Returns an instance of a BreakIterator implementing title breaks.
+     * The iterator returned locates title boundaries as described for
+     * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,
+     * please use Word Boundary iterator.{@link #createWordInstance }
+     *
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for title-breaks.  The UErrorCode& status
+     * parameter is used to return status information to the user.
+     * To check whether the construction succeeded or not, you should check
+     * the value of U_SUCCESS(err).  If you wish more detailed information, you
+     * can check for informational error results which still indicate success.
+     * U_USING_FALLBACK_WARNING indicates that a fall back locale was used.  For
+     * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+     * used.  U_USING_DEFAULT_WARNING indicates that the default locale data was
+     * used; neither the requested locale nor any of its fall back locales
+     * could be found.
+     * The caller owns the returned object and is responsible for deleting it.
+     * @stable ICU 2.1
+     */
+    static BreakIterator* U_EXPORT2
+    createTitleInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Get the set of Locales for which TextBoundaries are installed.
+     * <p><b>Note:</b> this will not return locales added through the register
+     * call. To see the registered locales too, use the getAvailableLocales
+     * function that returns a StringEnumeration object </p>
+     * @param count the output parameter of number of elements in the locale list
+     * @return available locales
+     * @stable ICU 2.0
+     */
+    static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+    /**
+     * Get name of the object for the desired Locale, in the desired langauge.
+     * @param objectLocale must be from getAvailableLocales.
+     * @param displayLocale specifies the desired locale for output.
+     * @param name the fill-in parameter of the return value
+     * Uses best match.
+     * @return user-displayable name
+     * @stable ICU 2.0
+     */
+    static UnicodeString& U_EXPORT2 getDisplayName(const Locale& objectLocale,
+                                         const Locale& displayLocale,
+                                         UnicodeString& name);
+
+    /**
+     * Get name of the object for the desired Locale, in the langauge of the
+     * default locale.
+     * @param objectLocale must be from getMatchingLocales
+     * @param name the fill-in parameter of the return value
+     * @return user-displayable name
+     * @stable ICU 2.0
+     */
+    static UnicodeString& U_EXPORT2 getDisplayName(const Locale& objectLocale,
+                                         UnicodeString& name);
+
+    /**
+     * Thread safe client-buffer-based cloning operation
+     *    Do NOT call delete on a safeclone, since 'new' is not used to create it.
+     * @param stackBuffer user allocated space for the new clone. If NULL new memory will be allocated.
+     * If buffer is not large enough, new memory will be allocated.
+     * @param BufferSize reference to size of allocated space.
+     * If BufferSize == 0, a sufficient size for use in cloning will
+     * be returned ('pre-flighting')
+     * If BufferSize is not enough for a stack-based safe clone,
+     * new memory will be allocated.
+     * @param status to indicate whether the operation went on smoothly or there were errors
+     *  An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were
+     *  necessary.
+     * @return pointer to the new clone
+     *
+     * @stable ICU 2.0
+     */
+    virtual BreakIterator *  createBufferClone(void *stackBuffer,
+                                               int32_t &BufferSize,
+                                               UErrorCode &status) = 0;
+
+    /**
+     *   Determine whether the BreakIterator was created in user memory by
+     *   createBufferClone(), and thus should not be deleted.  Such objects
+     *   must be closed by an explicit call to the destructor (not delete).
+     *  @stable ICU 2.0
+     */
+    inline UBool isBufferClone(void);
+
+#if !UCONFIG_NO_SERVICE
+    /**
+     * Register a new break iterator of the indicated kind, to use in the given locale.
+     * The break iterator will be adopted.  Clones of the iterator will be returned
+     * if a request for a break iterator of the given kind matches or falls back to
+     * this locale.
+     * @param toAdopt the BreakIterator instance to be adopted
+     * @param locale the Locale for which this instance is to be registered
+     * @param kind the type of iterator for which this instance is to be registered
+     * @param status the in/out status code, no special meanings are assigned
+     * @return a registry key that can be used to unregister this instance
+     * @stable ICU 2.4
+     */
+    static URegistryKey U_EXPORT2 registerInstance(BreakIterator* toAdopt,
+                                        const Locale& locale,
+                                        UBreakIteratorType kind,
+                                        UErrorCode& status);
+
+    /**
+     * Unregister a previously-registered BreakIterator using the key returned from the
+     * register call.  Key becomes invalid after a successful call and should not be used again.
+     * The BreakIterator corresponding to the key will be deleted.
+     * @param key the registry key returned by a previous call to registerInstance
+     * @param status the in/out status code, no special meanings are assigned
+     * @return TRUE if the iterator for the key was successfully unregistered
+     * @stable ICU 2.4
+     */
+    static UBool U_EXPORT2 unregister(URegistryKey key, UErrorCode& status);
+
+    /**
+     * Return a StringEnumeration over the locales available at the time of the call,
+     * including registered locales.
+     * @return a StringEnumeration over the locales available at the time of the call
+     * @stable ICU 2.4
+     */
+    static StringEnumeration* U_EXPORT2 getAvailableLocales(void);
+#endif
+
+    /**
+     * Returns the locale for this break iterator. Two flavors are available: valid and
+     * actual locale.
+     * @stable ICU 2.8
+     */
+    Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+    /** Get the locale for this break iterator object. You can choose between valid and actual locale.
+     *  @param type type of the locale we're looking for (valid or actual)
+     *  @param status error code for the operation
+     *  @return the locale
+     *  @internal
+     */
+    const char *getLocaleID(ULocDataLocaleType type, UErrorCode& status) const;
+
+ private:
+    static BreakIterator* buildInstance(const Locale& loc, const char *type, int32_t kind, UErrorCode& status);
+    static BreakIterator* createInstance(const Locale& loc, int32_t kind, UErrorCode& status);
+    static BreakIterator* makeInstance(const Locale& loc, int32_t kind, UErrorCode& status);
+
+    friend class ICUBreakIteratorFactory;
+    friend class ICUBreakIteratorService;
+
+protected:
+    /** @internal */
+    BreakIterator();
+    /** @internal */
+    UBool fBufferClone;
+    /** @internal */
+    BreakIterator (const BreakIterator &other) : UObject(other), fBufferClone(FALSE) {}
+
+private:
+
+    /** @internal */
+    char actualLocale[ULOC_FULLNAME_CAPACITY];
+    char validLocale[ULOC_FULLNAME_CAPACITY];
+
+    /**
+     * The assignment operator has no real implementation.
+     * It's provided to make the compiler happy. Do not call.
+     */
+    BreakIterator& operator=(const BreakIterator&);
+};
+
+inline UBool BreakIterator::isBufferClone()
+{
+    return fBufferClone;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif // _BRKITER
+//eof
+


Mime
View raw message