Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e8dbbf16 | ||
|
|
be7e6565f1 | ||
|
|
c0770bace0 | ||
|
|
788a3cf242 | ||
|
|
598c33d246 | ||
|
|
2bfd924ca8 | ||
|
|
28f553aa63 | ||
|
|
ae2da553e8 | ||
|
|
e96fd72841 | ||
|
|
9d9417ec1b | ||
|
|
3006ace8f5 | ||
|
|
b558b90253 | ||
|
|
a97fcf932c | ||
|
|
f438efbfca | ||
|
|
d0dd0bd0e4 | ||
|
|
77b5fe0e9f | ||
|
|
dbc6127820 | ||
|
|
2eb77e12f0 | ||
|
|
ffb626602c | ||
|
|
f571fb74c4 | ||
|
|
7c07476db7 | ||
|
|
e3be6dd0e9 | ||
|
|
c076fdb030 | ||
|
|
173c57fed2 | ||
|
|
737ac62926 | ||
|
|
9dcc0e140b | ||
|
|
e4e5481ca1 | ||
|
|
c3df6806b3 | ||
|
|
6dc523074d | ||
|
|
5746cbf1e3 | ||
|
|
51966e92a7 | ||
|
|
498057c51b | ||
|
|
b3c26a8633 | ||
|
|
5e218e77bf | ||
|
|
56fbf2a399 | ||
|
|
c3582f9617 | ||
|
|
bd83a45215 | ||
|
|
52dc944cfb | ||
|
|
3d27c749e1 | ||
|
|
75d679cdc8 | ||
|
|
2c9f28ecc3 | ||
|
|
9decf4c78a | ||
|
|
e2463a5589 | ||
|
|
a825f5a0c8 | ||
|
|
3c0d26cb74 | ||
|
|
f7a31ac804 | ||
|
|
31aebcdc59 | ||
|
|
afbac81918 | ||
|
|
0b78f86f08 | ||
|
|
7180b98f47 | ||
|
|
021cca436d | ||
|
|
a3d88dc406 | ||
|
|
58a6291f17 | ||
|
|
81884247d7 | ||
|
|
c07a34f9a8 | ||
|
|
e05bfc78cb | ||
|
|
cb430702c9 | ||
|
|
6aaa4bb06d | ||
|
|
a6b80a19c5 | ||
|
|
8be0ad0499 | ||
|
|
8da4936ac3 | ||
|
|
bcc92ccc40 | ||
|
|
d64d4b009c |
@@ -85,6 +85,65 @@ ask Mix to use Rebar 3 to compile it by passing the `manager: :rebar3` option.
|
||||
Once configured, Mix will prompt you to install Rebar 3 if it is not yet
|
||||
available.
|
||||
|
||||
## v1.2.4 (2016-04-01)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
* [Mix] Add `:archives` configuration to `def project` that allows projects to list archive dependencies. `--no-archives-check` (as well as `--no-deps-check`) will disable the archive check. The `:archives` option is not checked for dependencies.
|
||||
* [Mix] Add `deps.precompile` task as hook
|
||||
* [Mix] Support `--include-children` in `mix deps.compile` option
|
||||
* [String] Update version of the Unicode database to 8.0.0
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
* [Application] Ensure `spec/2` returns nil for unknown applications
|
||||
* [Integer] Fix a possible binary leak in `parse/1`
|
||||
* [Mix] Purge Erlang modules on recompilation
|
||||
* [String] Ensure `split/1` does not break on non-breakable whitespace
|
||||
* [String] Ensure NFC and NFD normalization pass all of Unicode 8.0.0 tests
|
||||
* [Version] Allow dots in build info for versions in `Version.parse/1`
|
||||
|
||||
## v1.2.3 (2016-02-21)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
* [Base] Add `:ignore` and `:padding` option to encoding/decoding functions
|
||||
* [Mix] Add `Mix.Projects.deps_paths` that returns the dependencies path as a map
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
* [ExUnit] Do not provide negative line numbers without generated annotation (for compatibility with Erlang 19)
|
||||
* [Mix] Reject non fullfilled optional dependencies later on in the convergence resolution for proper dependency sorting
|
||||
* [String] Fix incomplete data trimming on both `String.replace_trailing` and `String.rstrip`
|
||||
* [String] Attach debug_info back into Unicode modules for Dialyzer support
|
||||
|
||||
## v1.2.2 (2016-01-31)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
* [Kernel] Support `@compile {:autoload, false}` to disable automatic loading after compilation
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
* [ExUnit] Raise if trying to override reserved tag in `setup` blocks
|
||||
* [Mix] Ensure retrieve compile manifests do fail if some compilers are not yet available
|
||||
* [Mix] Automatically merge managers according to the mix > rebar3 > rebar > make order
|
||||
* [Mix] Force recompilation if dependency was recently fetched
|
||||
|
||||
## v1.2.1 (2016-01-14)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
* [IEx] Support remote pids/ports with IEx helper `i/1`
|
||||
* [Protocol] Warn when `defimpl` is called for a consolidated protocol
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
* [ExUnit] Ensure `assert` macros can be used from quoted code
|
||||
* [ExUnit] Do not warn in match assertion if variable is reused in pattern
|
||||
* [Macro] Fix a bug in `Macro.to_string/1` where a remote function could be accidentally interpreted as a sigil
|
||||
* [Mix] Ensure dependencies are properly skipped when `--only` option is given to `mix deps.get`
|
||||
|
||||
## v1.2.0 (2016-01-01)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
REBAR ?= "$(CURDIR)/rebar"
|
||||
PREFIX ?= /usr/local
|
||||
DOCS := master
|
||||
DOCS := v1.2
|
||||
CANONICAL := stable
|
||||
ELIXIRC := bin/elixirc --verbose --ignore-module-conflict
|
||||
ERLC := erlc -I lib/elixir/include
|
||||
ERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin
|
||||
@@ -128,7 +129,7 @@ clean_exbeam:
|
||||
|
||||
LOGO_PATH = $(shell test -f ../docs/logo.png && echo "--logo ../docs/logo.png")
|
||||
SOURCE_REF = $(shell head="$$(git rev-parse HEAD)" tag="$$(git tag --points-at $$head | tail -1)" ; echo "$${tag:-$$head}\c")
|
||||
COMPILE_DOCS = bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" -m "$(3)" -u "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) -o doc/$(2) -p http://elixir-lang.org/docs.html $(4)
|
||||
COMPILE_DOCS = bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" -m "$(3)" -u "https://github.com/elixir-lang/elixir" --source-ref "v$(VERSION)" $(call LOGO_PATH) -o doc/$(2) -a http://elixir-lang.org/docs/$(CANONICAL)/$(2)/ -p http://elixir-lang.org/docs.html $(4)
|
||||
|
||||
docs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger
|
||||
|
||||
|
||||
+1
-3
@@ -30,12 +30,10 @@ This document simply outlines the release process:
|
||||
|
||||
12. Create a new branch "vMAJOR.MINOR"
|
||||
|
||||
13. Move docs generation to `docs/vMAJOR.MINOR` in Makefile and copy them from `docs/stable`
|
||||
13. Move docs generation to `docs/vMAJOR.MINOR` in Makefile and copy them from `docs/stable` (change index.html accordingly)
|
||||
|
||||
14. In master, bump versions, start new CHANGELOG, add `-dev` back and commit "Start vVERSION+1"
|
||||
|
||||
15. `make release_docs` and push it to `elixir-lang/docs`
|
||||
|
||||
## Places where version is mentioned
|
||||
|
||||
* VERSION (make sure there is no newline in this file)
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
defmodule Access do
|
||||
@moduledoc """
|
||||
Dictionary-like access to data structures via the `foo[bar]` syntax.
|
||||
Key-based access to data structures via the `foo[bar]` syntax.
|
||||
|
||||
This module also empowers `Kernel`s nested update functions
|
||||
`Kernel.get_in/2`, `Kernel.put_in/3`, `Kernel.update_in/3` and
|
||||
`Kernel.get_and_update_in/3`.
|
||||
Elixir provides two syntaxes for accessing values. `user[:name]`
|
||||
is used by dynamic structures, like maps and keywords, while
|
||||
`user.name` is used by structs. The main difference is that
|
||||
`user[:name]` won't raise if the key `:name` is missing but
|
||||
`user.name` will raise if there is no `:name` key.
|
||||
|
||||
## Examples
|
||||
## Key-based lookups
|
||||
|
||||
Out of the box, Access works with built-in dictionaries: `Keyword`
|
||||
and `Map`:
|
||||
Out of the box, Access works with `Keyword` and `Map`:
|
||||
|
||||
iex> keywords = [a: 1, b: 2]
|
||||
iex> keywords[:a]
|
||||
@@ -23,13 +24,67 @@ defmodule Access do
|
||||
iex> star_ratings[1.5]
|
||||
"★☆"
|
||||
|
||||
Access can be combined with `Kernel.put_in/3` to put a value
|
||||
in a given key:
|
||||
|
||||
iex> map = %{a: 1, b: 2}
|
||||
iex> put_in map[:a], 3
|
||||
%{a: 3, b: 2}
|
||||
|
||||
This syntax is very convenient as it can be nested arbitrarily:
|
||||
|
||||
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
|
||||
iex> put_in users["john"][:age], 28
|
||||
%{"john" => %{age: 28}, "meg" => %{age: 23}}
|
||||
|
||||
Furthermore, Access transparently ignores `nil` values:
|
||||
|
||||
iex> keywords = [a: 1, b: 2]
|
||||
iex> keywords[:c][:unknown]
|
||||
nil
|
||||
|
||||
The key comparison must be implemented using the `===` operator.
|
||||
Since Access is a behaviour, it can be implemented to key-value
|
||||
data structures. Access requires the key comparison to be
|
||||
implemented using the `===` operator.
|
||||
|
||||
## Field-based lookups
|
||||
|
||||
The Access syntax (`foo[bar]`) cannot be used to access fields in
|
||||
structs. That's by design, as Access is meant to be used for
|
||||
dynamic key-value structures, like maps and keywords, and not
|
||||
by static ones like structs.
|
||||
|
||||
However Elixir already provides a field-based lookup for structs.
|
||||
Imagine a struct named `User` with name and age fields. The
|
||||
following would raise:
|
||||
|
||||
user = %User{name: "john"}
|
||||
user[:name]
|
||||
** (UndefinedFunctionError) undefined function User.fetch/2
|
||||
(User does not implement the Access behaviour)
|
||||
|
||||
Structs instead use the `user.name` syntax:
|
||||
|
||||
user.name
|
||||
#=> "john"
|
||||
|
||||
The same `user.name` syntax can also be used by `Kernel.put_in/2`
|
||||
to for updating structs fields:
|
||||
|
||||
put_in user.name, "mary"
|
||||
%User{name: "mary"}
|
||||
|
||||
Differently from `user[:name]`, `user.name` cannot be extended by
|
||||
the developers, and will be always restricted to only maps and
|
||||
structs.
|
||||
|
||||
Summing up:
|
||||
|
||||
* `user[:name]` is used by dynamic structures, is extensible and
|
||||
does not raise on missing keys
|
||||
* `user.name` is used by static structures, it is not extensible
|
||||
and it will raise on missing keys
|
||||
|
||||
"""
|
||||
|
||||
@type t :: list | map | nil
|
||||
@@ -39,6 +94,20 @@ defmodule Access do
|
||||
@callback fetch(t, key) :: {:ok, value} | :error
|
||||
@callback get_and_update(t, key, (value -> {value, value})) :: {value, t}
|
||||
|
||||
defmacrop raise_undefined_behaviour(e, struct, top) do
|
||||
quote do
|
||||
stacktrace = System.stacktrace
|
||||
e =
|
||||
case stacktrace do
|
||||
[unquote(top)|_] ->
|
||||
%{unquote(e) | reason: "#{inspect unquote(struct)} does not implement the Access behaviour"}
|
||||
_ ->
|
||||
unquote(e)
|
||||
end
|
||||
reraise e, stacktrace
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Fetches the container's value for the given key.
|
||||
"""
|
||||
@@ -47,6 +116,9 @@ defmodule Access do
|
||||
|
||||
def fetch(%{__struct__: struct} = container, key) do
|
||||
struct.fetch(container, key)
|
||||
rescue
|
||||
e in UndefinedFunctionError ->
|
||||
raise_undefined_behaviour e, struct, {^struct, :fetch, [^container, ^key], _}
|
||||
end
|
||||
|
||||
def fetch(%{} = map, key) do
|
||||
@@ -96,6 +168,9 @@ defmodule Access do
|
||||
|
||||
def get_and_update(%{__struct__: struct} = container, key, fun) do
|
||||
struct.get_and_update(container, key, fun)
|
||||
rescue
|
||||
e in UndefinedFunctionError ->
|
||||
raise_undefined_behaviour e, struct, {^struct, :get_and_update, [^container, ^key, ^fun], _}
|
||||
end
|
||||
|
||||
def get_and_update(%{} = map, key, fun) do
|
||||
|
||||
@@ -133,14 +133,16 @@ defmodule Application do
|
||||
@doc """
|
||||
Returns the value for `key` in `app`'s specification.
|
||||
|
||||
See `spec/1` for the supporte keys. If the given
|
||||
See `spec/1` for the supported keys. If the given
|
||||
specification parameter does not exist, this function
|
||||
will raise.
|
||||
will raise. Returns `nil` if the application is not loaded.
|
||||
"""
|
||||
@spec spec(app, key) :: value
|
||||
@spec spec(app, key) :: value | nil
|
||||
def spec(app, key) when key in @application_keys do
|
||||
{:ok, value} = :application.get_key(app, key)
|
||||
value
|
||||
case :application.get_key(app, key) do
|
||||
{:ok, value} -> value
|
||||
:undefined -> nil
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
+244
-127
@@ -138,6 +138,15 @@ defmodule Base do
|
||||
defp from_mixed(char),
|
||||
do: char
|
||||
|
||||
defp maybe_pad(subject, false, _, _),
|
||||
do: subject
|
||||
defp maybe_pad(subject, _, group_size, pad) do
|
||||
case rem(byte_size(subject), group_size) do
|
||||
0 -> subject
|
||||
x -> subject <> String.duplicate(pad, group_size - x)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Encodes a binary string into a base 16 encoded string.
|
||||
|
||||
@@ -225,29 +234,56 @@ defmodule Base do
|
||||
@doc """
|
||||
Encodes a binary string into a base 64 encoded string.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.encode64("foobar")
|
||||
"Zm9vYmFy"
|
||||
|
||||
iex> Base.encode64("foob")
|
||||
"Zm9vYg=="
|
||||
|
||||
iex> Base.encode64("foob", padding: false)
|
||||
"Zm9vYg"
|
||||
|
||||
"""
|
||||
@spec encode64(binary) :: binary
|
||||
def encode64(data) when is_binary(data) do
|
||||
do_encode64(data)
|
||||
@spec encode64(binary, Keyword.t) :: binary
|
||||
def encode64(data, opts \\ []) when is_binary(data) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_encode64(data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Decodes a base 64 encoded string into a binary string.
|
||||
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.decode64("Zm9vYmFy")
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.decode64("Zm9vYmFy\\n", ignore: :whitespace)
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.decode64("Zm9vYg==")
|
||||
{:ok, "foob"}
|
||||
|
||||
iex> Base.decode64("Zm9vYg", padding: false)
|
||||
{:ok, "foob"}
|
||||
|
||||
"""
|
||||
@spec decode64(binary) :: {:ok, binary} | :error
|
||||
def decode64(string) when is_binary(string) do
|
||||
{:ok, decode64!(string)}
|
||||
@spec decode64(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
def decode64(string, opts \\ []) when is_binary(string) do
|
||||
{:ok, decode64!(string, opts)}
|
||||
rescue
|
||||
ArgumentError -> :error
|
||||
end
|
||||
@@ -255,7 +291,11 @@ defmodule Base do
|
||||
@doc """
|
||||
Decodes a base 64 encoded string into a binary string.
|
||||
|
||||
The following alphabet is used both for encoding and decoding:
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
@@ -265,44 +305,72 @@ defmodule Base do
|
||||
iex> Base.decode64!("Zm9vYmFy")
|
||||
"foobar"
|
||||
|
||||
iex> Base.decode64!("Zm9vYmFy\\n", ignore: :whitespace)
|
||||
"foobar"
|
||||
|
||||
iex> Base.decode64!("Zm9vYg==")
|
||||
"foob"
|
||||
|
||||
iex> Base.decode64!("Zm9vYg", padding: false)
|
||||
"foob"
|
||||
|
||||
"""
|
||||
@spec decode64!(binary) :: binary
|
||||
def decode64!(string) when is_binary(string) and rem(byte_size(string), 4) == 0 do
|
||||
do_decode64(string)
|
||||
end
|
||||
|
||||
def decode64!(string) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
@spec decode64!(binary, Keyword.t) :: binary
|
||||
def decode64!(string, opts \\ []) when is_binary(string) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
string |> filter_ignored(opts[:ignore]) |> do_decode64(pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Encodes a binary string into a base 64 encoded string with URL and filename
|
||||
safe alphabet.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.url_encode64(<<255, 127, 254, 252>>)
|
||||
"_3_-_A=="
|
||||
|
||||
iex> Base.url_encode64(<<255, 127, 254, 252>>, padding: false)
|
||||
"_3_-_A"
|
||||
|
||||
"""
|
||||
@spec url_encode64(binary) :: binary
|
||||
def url_encode64(data) when is_binary(data) do
|
||||
do_encode64url(data)
|
||||
@spec url_encode64(binary, Keyword.t) :: binary
|
||||
def url_encode64(data, opts \\ []) when is_binary(data) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_encode64url(data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Decodes a base 64 encoded string with URL and filename safe alphabet
|
||||
into a binary string.
|
||||
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.url_decode64("_3_-_A==")
|
||||
{:ok, <<255, 127, 254, 252>>}
|
||||
|
||||
iex> Base.url_decode64("_3_-_A==\\n", ignore: :whitespace)
|
||||
{:ok, <<255, 127, 254, 252>>}
|
||||
|
||||
iex> Base.url_decode64("_3_-_A", padding: false)
|
||||
{:ok, <<255, 127, 254, 252>>}
|
||||
|
||||
"""
|
||||
@spec url_decode64(binary) :: {:ok, binary} | :error
|
||||
def url_decode64(string) when is_binary(string) do
|
||||
{:ok, url_decode64!(string)}
|
||||
@spec url_decode64(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
def url_decode64(string, opts \\ []) when is_binary(string) do
|
||||
{:ok, url_decode64!(string, opts)}
|
||||
rescue
|
||||
ArgumentError -> :error
|
||||
end
|
||||
@@ -311,6 +379,12 @@ defmodule Base do
|
||||
Decodes a base 64 encoded string with URL and filename safe alphabet
|
||||
into a binary string.
|
||||
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
|
||||
@@ -319,14 +393,18 @@ defmodule Base do
|
||||
iex> Base.url_decode64!("_3_-_A==")
|
||||
<<255, 127, 254, 252>>
|
||||
|
||||
iex> Base.url_decode64!("_3_-_A==\\n", ignore: :whitespace)
|
||||
<<255, 127, 254, 252>>
|
||||
|
||||
iex> Base.url_decode64!("_3_-_A", padding: false)
|
||||
<<255, 127, 254, 252>>
|
||||
|
||||
"""
|
||||
@spec url_decode64!(binary) :: binary
|
||||
def url_decode64!(string) when is_binary(string) and rem(byte_size(string), 4) == 0 do
|
||||
do_decode64url(string)
|
||||
end
|
||||
|
||||
def url_decode64!(string) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
@spec url_decode64!(binary, Keyword.t) :: binary
|
||||
def url_decode64!(string, opts \\ []) when is_binary(string) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
string |> filter_ignored(opts[:ignore]) |> do_decode64url(pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -335,6 +413,9 @@ defmodule Base do
|
||||
Accepts an atom `:upper` (default) for encoding to upper case characters or
|
||||
`:lower` for lower case characters.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.encode32("foobar")
|
||||
@@ -343,12 +424,16 @@ defmodule Base do
|
||||
iex> Base.encode32("foobar", case: :lower)
|
||||
"mzxw6ytboi======"
|
||||
|
||||
iex> Base.encode32("foobar", padding: false)
|
||||
"MZXW6YTBOI"
|
||||
|
||||
"""
|
||||
@spec encode32(binary) :: binary
|
||||
@spec encode32(binary, Keyword.t) :: binary
|
||||
def encode32(data, opts \\ []) when is_binary(data) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_encode32(case, data)
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_encode32(case, data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -358,6 +443,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.decode32("MZXW6YTBOI======")
|
||||
@@ -369,6 +457,9 @@ defmodule Base do
|
||||
iex> Base.decode32("mzXW6ytBOi======", case: :mixed)
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.decode32("MZXW6YTBOI", padding: false)
|
||||
{:ok, "foobar"}
|
||||
|
||||
"""
|
||||
@spec decode32(binary) :: {:ok, binary} | :error
|
||||
@spec decode32(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
@@ -385,6 +476,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
|
||||
@@ -399,18 +493,16 @@ defmodule Base do
|
||||
iex> Base.decode32!("mzXW6ytBOi======", case: :mixed)
|
||||
"foobar"
|
||||
|
||||
iex> Base.decode32!("MZXW6YTBOI", padding: false)
|
||||
"foobar"
|
||||
|
||||
"""
|
||||
@spec decode32!(binary) :: binary
|
||||
@spec decode32!(binary, Keyword.t) :: binary
|
||||
def decode32!(string, opts \\ [])
|
||||
|
||||
def decode32!(string, opts) when is_binary(string) and rem(byte_size(string), 8) == 0 do
|
||||
def decode32!(string, opts \\ []) when is_binary(string) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_decode32(case, string)
|
||||
end
|
||||
|
||||
def decode32!(string, _opts) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_decode32(case, string, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -420,6 +512,9 @@ defmodule Base do
|
||||
Accepts an atom `:upper` (default) for encoding to upper case characters or
|
||||
`:lower` for lower case characters.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.hex_encode32("foobar")
|
||||
@@ -428,12 +523,16 @@ defmodule Base do
|
||||
iex> Base.hex_encode32("foobar", case: :lower)
|
||||
"cpnmuoj1e8======"
|
||||
|
||||
iex> Base.hex_encode32("foobar", padding: false)
|
||||
"CPNMUOJ1E8"
|
||||
|
||||
"""
|
||||
@spec hex_encode32(binary) :: binary
|
||||
@spec hex_encode32(binary, Keyword.t) :: binary
|
||||
def hex_encode32(data, opts \\ []) when is_binary(data) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_hex_encode32(case, data)
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_hex_encode32(case, data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -444,6 +543,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.hex_decode32("CPNMUOJ1E8======")
|
||||
@@ -455,6 +557,9 @@ defmodule Base do
|
||||
iex> Base.hex_decode32("cpnMuOJ1E8======", case: :mixed)
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.hex_decode32("CPNMUOJ1E8", padding: false)
|
||||
{:ok, "foobar"}
|
||||
|
||||
"""
|
||||
@spec hex_decode32(binary) :: {:ok, binary} | :error
|
||||
@spec hex_decode32(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
@@ -472,6 +577,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
|
||||
@@ -486,18 +594,21 @@ defmodule Base do
|
||||
iex> Base.hex_decode32!("cpnMuOJ1E8======", case: :mixed)
|
||||
"foobar"
|
||||
|
||||
iex> Base.hex_decode32!("CPNMUOJ1E8", padding: false)
|
||||
"foobar"
|
||||
|
||||
"""
|
||||
@spec hex_decode32!(binary) :: binary
|
||||
@spec hex_decode32!(binary, Keyword.t) :: binary
|
||||
def hex_decode32!(string, opts \\ [])
|
||||
|
||||
def hex_decode32!(string, opts) when is_binary(string) and rem(byte_size(string), 8) == 0 do
|
||||
def hex_decode32!(string, opts \\ []) when is_binary(string) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_hex_decode32(case, string)
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_hex_decode32(case, string, pad_flag)
|
||||
end
|
||||
|
||||
def hex_decode32!(string, _opts) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
defp filter_ignored(string, nil), do: string
|
||||
defp filter_ignored(string, :whitespace) do
|
||||
for <<c::8 <- string>>, not c in '\s\t\r\n', into: <<>>, do: <<c::8>>
|
||||
end
|
||||
|
||||
defp do_encode16(_, <<>>), do: <<>>
|
||||
@@ -525,213 +636,219 @@ defmodule Base do
|
||||
end
|
||||
end
|
||||
|
||||
defp do_encode64(<<>>), do: <<>>
|
||||
defp do_encode64(data) do
|
||||
defp do_encode64(<<>>, _), do: <<>>
|
||||
defp do_encode64(data, pad_flag) do
|
||||
split = 3 * div(byte_size(data), 3)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::6 <- main>>, into: <<>>, do: <<enc64(c)::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::6, c2::6, c3::4>> ->
|
||||
<<main::binary, enc64(c1)::8, enc64(c2)::8, enc64(bsl(c3, 2))::8, ?=>>
|
||||
<<enc64(c1)::8, enc64(c2)::8, enc64(bsl(c3, 2))::8>>
|
||||
<<c1::6, c2::2>> ->
|
||||
<<main::binary, enc64(c1)::8, enc64(bsl(c2, 4))::8, ?=, ?=>>
|
||||
<<enc64(c1)::8, enc64(bsl(c2, 4))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 4, "=")
|
||||
end
|
||||
|
||||
defp do_decode64(<<>>), do: <<>>
|
||||
defp do_decode64(string) do
|
||||
defp do_decode64(<<>>, _), do: <<>>
|
||||
defp do_decode64(string, false) do
|
||||
maybe_pad(string, true, 4, "=") |> do_decode64(true)
|
||||
end
|
||||
defp do_decode64(string, _pad_flag) when rem(byte_size(string), 4) == 0 do
|
||||
split = byte_size(string) - 4
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec64(c)::6>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=>> ->
|
||||
<<main::binary, dec64(c1)::6, bsr(dec64(c2), 4)::2>>
|
||||
<<dec64(c1)::6, bsr(dec64(c2), 4)::2>>
|
||||
<<c1::8, c2::8, c3::8, ?=>> ->
|
||||
<<main::binary, dec64(c1)::6, dec64(c2)::6, bsr(dec64(c3), 2)::4>>
|
||||
<<dec64(c1)::6, dec64(c2)::6, bsr(dec64(c3), 2)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8>> ->
|
||||
<<main::binary, dec64(c1)::6, dec64(c2)::6, dec64(c3)::6, dec64(c4)::6>>
|
||||
<<dec64(c1)::6, dec64(c2)::6, dec64(c3)::6, dec64(c4)::6>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
defp do_decode64(_, _) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
end
|
||||
|
||||
defp do_encode64url(<<>>), do: <<>>
|
||||
defp do_encode64url(data) do
|
||||
defp do_encode64url(<<>>, _), do: <<>>
|
||||
defp do_encode64url(data, pad_flag) do
|
||||
split = 3 * div(byte_size(data), 3)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::6 <- main>>, into: <<>>, do: <<enc64url(c)::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::6, c2::6, c3::4>> ->
|
||||
<<main::binary, enc64url(c1)::8, enc64url(c2)::8, enc64url(bsl(c3, 2))::8, ?=>>
|
||||
<<enc64url(c1)::8, enc64url(c2)::8, enc64url(bsl(c3, 2))::8>>
|
||||
<<c1::6, c2::2>> ->
|
||||
<<main::binary, enc64url(c1)::8, enc64url(bsl(c2, 4))::8, ?=, ?=>>
|
||||
<<enc64url(c1)::8, enc64url(bsl(c2, 4))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 4, "=")
|
||||
end
|
||||
|
||||
defp do_decode64url(<<>>), do: <<>>
|
||||
defp do_decode64url(string) do
|
||||
defp do_decode64url(<<>>, _), do: <<>>
|
||||
defp do_decode64url(string, false) do
|
||||
maybe_pad(string, true, 4, "=") |> do_decode64url(true)
|
||||
end
|
||||
defp do_decode64url(string, _pad_flag) when rem(byte_size(string), 4) == 0 do
|
||||
split = byte_size(string) - 4
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec64url(c)::6>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=>> ->
|
||||
<<main::binary, dec64url(c1)::6, bsr(dec64url(c2), 4)::2>>
|
||||
<<dec64url(c1)::6, bsr(dec64url(c2), 4)::2>>
|
||||
<<c1::8, c2::8, c3::8, ?=>> ->
|
||||
<<main::binary, dec64url(c1)::6, dec64url(c2)::6, bsr(dec64url(c3), 2)::4>>
|
||||
<<dec64url(c1)::6, dec64url(c2)::6, bsr(dec64url(c3), 2)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8>> ->
|
||||
<<main::binary, dec64url(c1)::6, dec64url(c2)::6, dec64url(c3)::6, dec64url(c4)::6>>
|
||||
<<dec64url(c1)::6, dec64url(c2)::6, dec64url(c3)::6, dec64url(c4)::6>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
defp do_decode64url(_, _) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
end
|
||||
|
||||
|
||||
|
||||
defp do_encode32(_, <<>>), do: <<>>
|
||||
defp do_encode32(_, <<>>, _), do: <<>>
|
||||
|
||||
for {case, fun} <- [upper: :to_upper, lower: :to_lower] do
|
||||
defp do_encode32(unquote(case), data) do
|
||||
defp do_encode32(unquote(case), data, pad_flag) do
|
||||
split = 5 * div(byte_size(data), 5)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::5 <- main>>, into: <<>>, do: <<unquote(fun)(enc32(c))::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::5, c6::5, c7::2>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(c4))::8,
|
||||
unquote(fun)(enc32(c5))::8, unquote(fun)(enc32(c6))::8,
|
||||
unquote(fun)(enc32(bsl(c7, 3)))::8, ?=>>
|
||||
unquote(fun)(enc32(bsl(c7, 3)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::4>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(c4))::8,
|
||||
unquote(fun)(enc32(bsl(c5, 1)))::8, ?=, ?=, ?=>>
|
||||
unquote(fun)(enc32(bsl(c5, 1)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::1>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(bsl(c4, 4)))::8,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(bsl(c4, 4)))::8>>
|
||||
<<c1::5, c2::3>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(bsl(c2, 2)))::8, ?=, ?=,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(bsl(c2, 2)))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 8, "=")
|
||||
end
|
||||
end
|
||||
|
||||
defp do_decode32(_, <<>>), do: <<>>
|
||||
defp do_decode32(_, <<>>, _), do: <<>>
|
||||
defp do_decode32(case, string, false),
|
||||
do: do_decode32(case, maybe_pad(string, true, 8, "="), true)
|
||||
|
||||
for {case, fun} <- [upper: :from_upper, lower: :from_lower, mixed: :from_mixed] do
|
||||
defp do_decode32(unquote(case), string) do
|
||||
defp do_decode32(unquote(case), string, _pad_flag) when rem(byte_size(string), 8) == 0 do
|
||||
split = byte_size(string) - 8
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec32(unquote(fun)(c))::5>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary, dec32(unquote(fun)(c1))::5,
|
||||
bsr(dec32(unquote(fun)(c2)), 2)::3>>
|
||||
<<dec32(unquote(fun)(c1))::5, bsr(dec32(unquote(fun)(c2)), 2)::3>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, bsr(dec32(unquote(fun)(c4)), 4)::1>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, dec32(unquote(fun)(c4))::5,
|
||||
bsr(dec32(unquote(fun)(c5)), 1)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, dec32(unquote(fun)(c4))::5,
|
||||
dec32(unquote(fun)(c5))::5, dec32(unquote(fun)(c6))::5,
|
||||
bsr(dec32(unquote(fun)(c7)), 3)::2>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, dec32(unquote(fun)(c4))::5,
|
||||
dec32(unquote(fun)(c5))::5, dec32(unquote(fun)(c6))::5,
|
||||
dec32(unquote(fun)(c7))::5, dec32(unquote(fun)(c8))::5>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
end
|
||||
|
||||
defp do_hex_encode32(_, <<>>), do: <<>>
|
||||
defp do_decode32(_, _, _),
|
||||
do: raise ArgumentError, "incorrect padding"
|
||||
|
||||
defp do_hex_encode32(_, <<>>, _), do: <<>>
|
||||
|
||||
for {case, fun} <- [upper: :to_upper, lower: :to_lower] do
|
||||
defp do_hex_encode32(unquote(case), data) do
|
||||
defp do_hex_encode32(unquote(case), data, pad_flag) do
|
||||
split = 5 * div(byte_size(data), 5)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::5 <- main>>, into: <<>>, do: <<unquote(fun)(enc32hex(c))::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::5, c6::5, c7::2>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(c4))::8,
|
||||
unquote(fun)(enc32hex(c5))::8, unquote(fun)(enc32hex(c6))::8,
|
||||
unquote(fun)(enc32hex(bsl(c7, 3)))::8, ?=>>
|
||||
unquote(fun)(enc32hex(bsl(c7, 3)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::4>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(c4))::8,
|
||||
unquote(fun)(enc32hex(bsl(c5, 1)))::8, ?=, ?=, ?=>>
|
||||
unquote(fun)(enc32hex(bsl(c5, 1)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::1>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(bsl(c4, 4)))::8,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(bsl(c4, 4)))::8>>
|
||||
<<c1::5, c2::3>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(bsl(c2, 2)))::8, ?=, ?=,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(bsl(c2, 2)))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 8, "=")
|
||||
end
|
||||
end
|
||||
|
||||
defp do_hex_decode32(_, <<>>), do: <<>>
|
||||
defp do_hex_decode32(_, <<>>, _), do: <<>>
|
||||
defp do_hex_decode32(case, string, false),
|
||||
do: do_hex_decode32(case, maybe_pad(string, true, 8, "="), true)
|
||||
|
||||
for {case, fun} <- [upper: :from_upper, lower: :from_lower, mixed: :from_mixed] do
|
||||
defp do_hex_decode32(unquote(case), string) do
|
||||
defp do_hex_decode32(unquote(case), string, _pad_flag) when rem(byte_size(string), 8) == 0 do
|
||||
split = byte_size(string) - 8
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec32hex(unquote(fun)(c))::5>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary, dec32hex(unquote(fun)(c1))::5,
|
||||
bsr(dec32hex(unquote(fun)(c2)), 2)::3>>
|
||||
<<dec32hex(unquote(fun)(c1))::5, bsr(dec32hex(unquote(fun)(c2)), 2)::3>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, bsr(dec32hex(unquote(fun)(c4)), 4)::1>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, dec32hex(unquote(fun)(c4))::5,
|
||||
bsr(dec32hex(unquote(fun)(c5)), 1)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, dec32hex(unquote(fun)(c4))::5,
|
||||
dec32hex(unquote(fun)(c5))::5, dec32hex(unquote(fun)(c6))::5,
|
||||
bsr(dec32hex(unquote(fun)(c7)), 3)::2>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, dec32hex(unquote(fun)(c4))::5,
|
||||
dec32hex(unquote(fun)(c5))::5, dec32hex(unquote(fun)(c6))::5,
|
||||
dec32hex(unquote(fun)(c7))::5, dec32hex(unquote(fun)(c8))::5>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
end
|
||||
|
||||
defp do_hex_decode32(_, _, _),
|
||||
do: raise ArgumentError, "incorrect padding"
|
||||
end
|
||||
|
||||
@@ -640,6 +640,10 @@ defmodule UndefinedFunctionError do
|
||||
"undefined function " <> Exception.format_mfa(module, function, arity) <>
|
||||
" (function #{fa} is not available)"
|
||||
end
|
||||
|
||||
def message(%{reason: reason, module: module, function: function, arity: arity}) do
|
||||
"undefined function " <> Exception.format_mfa(module, function, arity) <> " (#{reason})"
|
||||
end
|
||||
end
|
||||
|
||||
defmodule FunctionClauseError do
|
||||
|
||||
@@ -48,7 +48,7 @@ defprotocol Inspect do
|
||||
implementation directly. For example, to test Inspect.MapSet above,
|
||||
you can invoke it as:
|
||||
|
||||
Inspect.MapSet.inspect(MapSet.new, Inspect.Opts.new)
|
||||
Inspect.MapSet.inspect(MapSet.new, %Inspect.Opts{})
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -167,11 +167,11 @@ defmodule Integer do
|
||||
|
||||
defp do_parse(_, _), do: :error
|
||||
|
||||
defp do_parse(<<char, rest::binary>>, base, acc) do
|
||||
defp do_parse(<<char, rest::binary>> = bin, base, acc) do
|
||||
if valid_digit_in_base?(char, base) do
|
||||
do_parse(rest, base, base * acc + parse_digit(char, base))
|
||||
else
|
||||
{acc, <<char, rest::binary>>}
|
||||
{acc, bin}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -571,6 +571,10 @@ defmodule Macro do
|
||||
fun.(ast, "&" <> to_string(mod, fun) <> "." <> Atom.to_string(name) <> "/" <> to_string(arity, fun))
|
||||
end
|
||||
|
||||
def to_string({:&, _, [arg]} = ast, fun) when not is_integer(arg) do
|
||||
fun.(ast, "&(" <> to_string(arg, fun) <> ")")
|
||||
end
|
||||
|
||||
# Unary ops
|
||||
def to_string({unary, _, [{binary, _, [_, _]} = arg]} = ast, fun)
|
||||
when unary in unquote(@unary_ops) and binary in unquote(@binary_ops) do
|
||||
@@ -691,7 +695,7 @@ defmodule Macro do
|
||||
defp module_to_string(atom, _fun) when is_atom(atom), do: inspect(atom, [])
|
||||
defp module_to_string(other, fun), do: call_to_string(other, fun)
|
||||
|
||||
defp sigil_call({func, _, [{:<<>>, _, _} = bin, args]} = ast, fun) when is_list(args) do
|
||||
defp sigil_call({func, _, [{:<<>>, _, _} = bin, args]} = ast, fun) when is_atom(func) and is_list(args) do
|
||||
sigil =
|
||||
case Atom.to_string(func) do
|
||||
<<"sigil_", name>> ->
|
||||
|
||||
@@ -540,6 +540,7 @@ defmodule Protocol do
|
||||
"the dict[key] syntax, please implement the Dict behaviour instead"
|
||||
else
|
||||
Protocol.assert_protocol!(protocol)
|
||||
Protocol.__ensure_defimpl__(protocol, for, __ENV__)
|
||||
end
|
||||
|
||||
defmodule name do
|
||||
@@ -580,6 +581,7 @@ defmodule Protocol do
|
||||
defp derive(protocol, for, struct, opts, env) do
|
||||
extra = ", cannot derive #{inspect protocol} for #{inspect for}"
|
||||
assert_protocol!(protocol, extra)
|
||||
__ensure_defimpl__(protocol, for, env)
|
||||
assert_impl!(protocol, Any, extra)
|
||||
|
||||
# Clean up variables from eval context
|
||||
@@ -608,6 +610,17 @@ defmodule Protocol do
|
||||
end)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def __ensure_defimpl__(protocol, for, env) do
|
||||
if Protocol.consolidated?(protocol) do
|
||||
message =
|
||||
"the #{inspect protocol} protocol has already been consolidated" <>
|
||||
", an implementation for #{inspect for} has no effect"
|
||||
:elixir_errors.warn(env.line, env.file, message)
|
||||
end
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc false
|
||||
def __spec__?(module, name, arity) do
|
||||
signature = {name, arity}
|
||||
|
||||
+25
-20
@@ -8,10 +8,10 @@ defmodule String do
|
||||
|
||||
The functions in this module act according to the Unicode
|
||||
Standard, version 6.3.0.
|
||||
|
||||
|
||||
As per the standard, a codepoint is a single Unicode Character,
|
||||
which may be represented by one or more bytes.
|
||||
|
||||
|
||||
For example, the codepoint "é" is two bytes:
|
||||
|
||||
iex> byte_size("é")
|
||||
@@ -239,9 +239,11 @@ defmodule String do
|
||||
def printable?(<<>>), do: true
|
||||
def printable?(binary) when is_binary(binary), do: false
|
||||
|
||||
@doc """
|
||||
@doc ~S"""
|
||||
Divides a string into substrings at each Unicode whitespace
|
||||
occurrence with leading and trailing whitespace ignored.
|
||||
occurrence with leading and trailing whitespace ignored. Groups
|
||||
of whitespace are treated as a single occurrence. Divisions do
|
||||
not occur on non-breaking whitespace.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -254,9 +256,12 @@ defmodule String do
|
||||
iex> String.split(" foo bar ")
|
||||
["foo", "bar"]
|
||||
|
||||
iex> String.split("no\u00a0break")
|
||||
["no\u00a0break"]
|
||||
|
||||
"""
|
||||
@spec split(t) :: [t]
|
||||
defdelegate split(binary), to: String.Unicode
|
||||
defdelegate split(binary), to: String.Break
|
||||
|
||||
@doc ~S"""
|
||||
Divides a string into substrings based on a pattern.
|
||||
@@ -444,7 +449,7 @@ defmodule String do
|
||||
end
|
||||
|
||||
defp do_split_at(string, position) do
|
||||
{byte_size, rest} = String.Graphemes.split_at(string, position)
|
||||
{byte_size, rest} = String.Unicode.split_at(string, position)
|
||||
{binary_part(string, 0, byte_size), rest || ""}
|
||||
end
|
||||
|
||||
@@ -499,7 +504,7 @@ defmodule String do
|
||||
## Examples
|
||||
|
||||
iex> String.normalize("yêṩ", :nfd)
|
||||
"yêṩ"
|
||||
"yêṩ"
|
||||
|
||||
iex> String.normalize("leña", :nfc)
|
||||
"leña"
|
||||
@@ -524,7 +529,7 @@ defmodule String do
|
||||
|
||||
"""
|
||||
@spec upcase(t) :: t
|
||||
defdelegate upcase(binary), to: String.Unicode
|
||||
defdelegate upcase(binary), to: String.Casing
|
||||
|
||||
@doc """
|
||||
Converts all characters in the given string to lowercase.
|
||||
@@ -542,7 +547,7 @@ defmodule String do
|
||||
|
||||
"""
|
||||
@spec downcase(t) :: t
|
||||
defdelegate downcase(binary), to: String.Unicode
|
||||
defdelegate downcase(binary), to: String.Casing
|
||||
|
||||
@doc """
|
||||
Converts the first character in the given string to
|
||||
@@ -567,7 +572,7 @@ defmodule String do
|
||||
"""
|
||||
@spec capitalize(t) :: t
|
||||
def capitalize(string) when is_binary(string) do
|
||||
{char, rest} = String.Unicode.titlecase_once(string)
|
||||
{char, rest} = String.Casing.titlecase_once(string)
|
||||
char <> downcase(rest)
|
||||
end
|
||||
|
||||
@@ -582,7 +587,7 @@ defmodule String do
|
||||
|
||||
"""
|
||||
@spec rstrip(t) :: t
|
||||
defdelegate rstrip(binary), to: String.Unicode
|
||||
defdelegate rstrip(binary), to: String.Break
|
||||
|
||||
@doc """
|
||||
Returns a string where all trailing `char`s have been removed.
|
||||
@@ -661,7 +666,7 @@ defmodule String do
|
||||
replace_trailing(string, match, replacement, prefix_size, suffix_size, "")
|
||||
end
|
||||
|
||||
defp replace_trailing(string, match, replacement, prefix_size, suffix_size, acc) when prefix_size > 0 do
|
||||
defp replace_trailing(string, match, replacement, prefix_size, suffix_size, acc) when prefix_size >= 0 do
|
||||
case string do
|
||||
<<prefix::size(prefix_size)-binary, suffix::size(suffix_size)-binary>> when suffix == match ->
|
||||
replace_trailing(prefix, match, replacement, prefix_size - suffix_size, suffix_size, acc <> replacement)
|
||||
@@ -754,7 +759,7 @@ defmodule String do
|
||||
"abc "
|
||||
|
||||
"""
|
||||
defdelegate lstrip(binary), to: String.Unicode
|
||||
defdelegate lstrip(binary), to: String.Break
|
||||
|
||||
@doc """
|
||||
Returns a string where all leading `char`s have been removed.
|
||||
@@ -1179,7 +1184,7 @@ defmodule String do
|
||||
|
||||
"""
|
||||
@spec graphemes(t) :: [grapheme]
|
||||
defdelegate graphemes(string), to: String.Graphemes
|
||||
defdelegate graphemes(string), to: String.Unicode
|
||||
|
||||
@compile {:inline, next_grapheme: 1, next_grapheme_size: 1}
|
||||
|
||||
@@ -1218,7 +1223,7 @@ defmodule String do
|
||||
|
||||
"""
|
||||
@spec next_grapheme_size(t) :: {pos_integer, t} | nil
|
||||
defdelegate next_grapheme_size(string), to: String.Graphemes
|
||||
defdelegate next_grapheme_size(string), to: String.Unicode
|
||||
|
||||
@doc """
|
||||
Returns the first grapheme from a utf8 string,
|
||||
@@ -1278,7 +1283,7 @@ defmodule String do
|
||||
|
||||
"""
|
||||
@spec length(t) :: non_neg_integer
|
||||
defdelegate length(string), to: String.Graphemes
|
||||
defdelegate length(string), to: String.Unicode
|
||||
|
||||
@doc """
|
||||
Returns the grapheme at the `position` of the given utf8 `string`.
|
||||
@@ -1317,7 +1322,7 @@ defmodule String do
|
||||
end
|
||||
|
||||
defp do_at(string, position) do
|
||||
case String.Graphemes.split_at(string, position) do
|
||||
case String.Unicode.split_at(string, position) do
|
||||
{_, nil} -> nil
|
||||
{_, rest} -> first(rest)
|
||||
end
|
||||
@@ -1367,10 +1372,10 @@ defmodule String do
|
||||
end
|
||||
|
||||
def slice(string, start, len) when start >= 0 and len >= 0 do
|
||||
case String.Graphemes.split_at(string, start) do
|
||||
case String.Unicode.split_at(string, start) do
|
||||
{_, nil} -> ""
|
||||
{start_bytes, rest} ->
|
||||
{len_bytes, _} = String.Graphemes.split_at(rest, len)
|
||||
{len_bytes, _} = String.Unicode.split_at(rest, len)
|
||||
binary_part(string, start_bytes, len_bytes)
|
||||
end
|
||||
end
|
||||
@@ -1438,7 +1443,7 @@ defmodule String do
|
||||
def slice("", _.._), do: ""
|
||||
|
||||
def slice(string, first..-1) when first >= 0 do
|
||||
case String.Graphemes.split_at(string, first) do
|
||||
case String.Unicode.split_at(string, first) do
|
||||
{_, nil} ->
|
||||
""
|
||||
{start_bytes, _} ->
|
||||
|
||||
@@ -317,7 +317,7 @@ defmodule Version do
|
||||
(?:\.(\d+))? # minor
|
||||
(?:\.(\d+))? # patch
|
||||
(?:\-([\d\w\.\-]+))? # pre
|
||||
(?:\+([\d\w\-]+))? # build
|
||||
(?:\+([\d\w\.\-]+))? # build
|
||||
$/x
|
||||
|
||||
@spec parse_requirement(String.t) :: {:ok, Version.Requirement.t} | :error
|
||||
|
||||
@@ -100,8 +100,8 @@ Built-in type | Defined as
|
||||
`list()` | `[any()]`
|
||||
`maybe_improper_list()` | `maybe_improper_list(any(), any())`
|
||||
`nonempty_list()` | `nonempty_list(any())`
|
||||
`iolist()` | `maybe_improper_list(byte() \| binary() \| iolist(), binary() \| [])`
|
||||
`iodata()` | `iolist()` \| `binary()`
|
||||
`iolist()` | `maybe_improper_list(byte()` \| `binary()` \| `iolist(), binary()` \| `[])`
|
||||
`module()` | `atom()` \| `tuple()`
|
||||
`arity()` | `0..255`
|
||||
`mfa()` | `{atom(), atom(), arity()}`
|
||||
|
||||
@@ -78,9 +78,8 @@ code_loading_compilation(Forms, Vars, #{line := Line} = E) ->
|
||||
|
||||
%% Pass {native, false} to speed up bootstrap
|
||||
%% process when native is set to true
|
||||
AllOpts = options(),
|
||||
FinalOpts = AllOpts -- [native, warn_missing_spec],
|
||||
inner_module(Form, FinalOpts, true, E, fun(_, Binary) ->
|
||||
ErlOpts = options() -- [native, warn_missing_spec],
|
||||
inner_module(Form, ErlOpts, [{bootstrap, true}], E, fun(_, Binary) ->
|
||||
%% If we have labeled locals, anonymous functions
|
||||
%% were created and therefore we cannot ditch the
|
||||
%% module
|
||||
@@ -169,22 +168,32 @@ allows_fast_compilation(_) -> false.
|
||||
%% executes the callback in case of success. This automatically
|
||||
%% handles errors and warnings. Used by this module and elixir_module.
|
||||
module(Forms, Opts, E, Callback) ->
|
||||
Final =
|
||||
case (get_opt(debug_info) == true) orelse
|
||||
lists:member(debug_info, Opts) of
|
||||
true -> [debug_info] ++ options();
|
||||
false -> options()
|
||||
ErlOpts =
|
||||
case proplists:get_value(debug_info, Opts) of
|
||||
true -> [debug_info];
|
||||
false -> [];
|
||||
undefined ->
|
||||
case get_opt(debug_info) of
|
||||
true -> [debug_info];
|
||||
false -> []
|
||||
end
|
||||
end,
|
||||
inner_module(Forms, Final, false, E, Callback).
|
||||
inner_module(Forms, ErlOpts ++ options(), Opts, E, Callback).
|
||||
|
||||
inner_module(Forms, Options, Bootstrap, #{file := File} = E, Callback) when
|
||||
is_list(Forms), is_list(Options), is_boolean(Bootstrap), is_function(Callback) ->
|
||||
inner_module(Forms, ErlOpts, ExOpts, #{file := File} = E, Callback) when
|
||||
is_list(Forms), is_list(ErlOpts), is_list(ExOpts), is_function(Callback) ->
|
||||
Source = elixir_utils:characters_to_list(File),
|
||||
Autoload = proplists:get_value(autoload, ExOpts, true),
|
||||
Bootstrap = proplists:get_value(bootstrap, ExOpts, false),
|
||||
|
||||
case compile:noenv_forms([no_auto_import()|Forms], [return, {source, Source}|Options]) of
|
||||
case compile:noenv_forms([no_auto_import()|Forms], [return, {source, Source}|ErlOpts]) of
|
||||
{ok, Module, Binary, Warnings} ->
|
||||
format_warnings(Bootstrap, Warnings),
|
||||
{module, Module} = code:load_binary(Module, beam_location(E), Binary),
|
||||
{module, Module} =
|
||||
case Autoload of
|
||||
true -> code:load_binary(Module, beam_location(E), Binary);
|
||||
false -> {module, Module}
|
||||
end,
|
||||
Callback(Module, Binary);
|
||||
{error, Errors, Warnings} ->
|
||||
format_warnings(Bootstrap, Warnings),
|
||||
|
||||
@@ -331,7 +331,7 @@ spec_for_macro(Else) -> Else.
|
||||
|
||||
compile_opts(Module) ->
|
||||
case ets:lookup(data_table(Module), compile) of
|
||||
[{compile, Opts}] when is_list(Opts) -> Opts;
|
||||
[{compile, Opts}] when is_list(Opts) -> lists:flatten(Opts);
|
||||
[] -> []
|
||||
end.
|
||||
|
||||
|
||||
@@ -59,4 +59,20 @@ defmodule AccessTest do
|
||||
assert Access.get_and_update(%{}, :foo, fn nil -> {:ok, :baz} end) == {:ok, %{foo: :baz}}
|
||||
assert Access.get_and_update(%{foo: :bar}, :foo, fn :bar -> {:ok, :baz} end) == {:ok, %{foo: :baz}}
|
||||
end
|
||||
|
||||
test "for struct" do
|
||||
defmodule Sample do
|
||||
defstruct [:name]
|
||||
end
|
||||
|
||||
assert_raise UndefinedFunctionError,
|
||||
"undefined function AccessTest.Sample.fetch/2 (AccessTest.Sample does not implement the Access behaviour)", fn ->
|
||||
Access.fetch(struct(Sample, []), :name)
|
||||
end
|
||||
|
||||
assert_raise UndefinedFunctionError,
|
||||
"undefined function AccessTest.Sample.get_and_update/3 (AccessTest.Sample does not implement the Access behaviour)", fn ->
|
||||
Access.get_and_update(struct(Sample, []), :name, fn nil -> {:ok, :baz} end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,6 +38,7 @@ defmodule ApplicationTest do
|
||||
test "application specification" do
|
||||
assert is_list Application.spec(:elixir)
|
||||
assert Application.spec(:unknown) == nil
|
||||
assert Application.spec(:unknown, :description) == nil
|
||||
|
||||
assert Application.spec(:elixir, :description) == 'elixir'
|
||||
assert_raise FunctionClauseError, fn -> Application.spec(:elixir, :unknown) end
|
||||
|
||||
@@ -93,6 +93,18 @@ defmodule BaseTest do
|
||||
assert "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" == encode64(<<"0123456789!@#0^&*();:<>,. []{}">>)
|
||||
end
|
||||
|
||||
test "encode64 omit padding one pad" do
|
||||
assert "SGVsbG8gV29ybGQ" == encode64("Hello World", padding: false)
|
||||
end
|
||||
|
||||
test "encode64 omit padding two pads" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2FtZQ" == encode64("Aladdin:open sesame", padding: false)
|
||||
end
|
||||
|
||||
test "encode64 omit padding no pad" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2Ft" == encode64("Aladdin:open sesam", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 empty" do
|
||||
assert {:ok, ""} == decode64("")
|
||||
end
|
||||
@@ -135,6 +147,18 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "decode64 whitespace" do
|
||||
assert :error == decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
assert {:ok, "Aladdin:open sesam"} == decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "decode64! whitespace" do
|
||||
assert_raise ArgumentError, "non-alphabet digit found: \"\\n\" (byte 10)", fn ->
|
||||
decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
end
|
||||
assert "Aladdin:open sesam" == decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "decode64 incorrect padding" do
|
||||
assert :error == decode64("SGVsbG8gV29ybGQ")
|
||||
end
|
||||
@@ -145,6 +169,38 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "decode64 ignore padding two pads" do
|
||||
assert {:ok, "Aladdin:open sesame"} == decode64("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding two pads" do
|
||||
assert "Aladdin:open sesame" == decode64!("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 ignore padding one pad" do
|
||||
assert {:ok, "Hello World"} == decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding one pad" do
|
||||
assert "Hello World" == decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 ignore padding no pad" do
|
||||
assert {:ok, "Aladdin:open sesam"} == decode64("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding no pad" do
|
||||
assert "Aladdin:open sesam" == decode64!("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 ignore padding incorrect padding" do
|
||||
assert {:ok, "Hello World"} == decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding incorrect padding" do
|
||||
assert "Hello World" == decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 empty" do
|
||||
assert "" == url_encode64("")
|
||||
end
|
||||
@@ -162,6 +218,18 @@ defmodule BaseTest do
|
||||
assert "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" == url_encode64(<<"0123456789!@#0^&*();:<>,. []{}">>)
|
||||
end
|
||||
|
||||
test "url_encode64 omit padding two pads" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2FtZQ" == url_encode64("Aladdin:open sesame", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 omit padding one pad" do
|
||||
assert "SGVsbG8gV29ybGQ" == url_encode64("Hello World", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 omit padding no pad" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2Ft" == url_encode64("Aladdin:open sesam", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 no URL unsafe characters" do
|
||||
refute "/3/+/A==" == url_encode64(<<255, 127, 254, 252>>)
|
||||
assert "_3_-_A==" == url_encode64(<<255, 127, 254, 252>>)
|
||||
@@ -199,6 +267,18 @@ defmodule BaseTest do
|
||||
assert "Aladdin:open sesam" == url_decode64!("QWxhZGRpbjpvcGVuIHNlc2Ft")
|
||||
end
|
||||
|
||||
test "url_decode64 whitespace" do
|
||||
assert :error == url_decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
assert {:ok, "Aladdin:open sesam"} == url_decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "url_decode64! whitespace" do
|
||||
assert_raise ArgumentError, "non-alphabet digit found: \"\\n\" (byte 10)", fn ->
|
||||
url_decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
end
|
||||
assert "Aladdin:open sesam" == url_decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "url_decode64 non-alphabet digit" do
|
||||
assert :error == url_decode64("Zm9)")
|
||||
end
|
||||
@@ -219,6 +299,38 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding two pads" do
|
||||
assert {:ok, "Aladdin:open sesame"} == url_decode64("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding two pads" do
|
||||
assert "Aladdin:open sesame" == url_decode64!("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding one pad" do
|
||||
assert {:ok, "Hello World"} == url_decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding one pad" do
|
||||
assert "Hello World" == url_decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding no pad" do
|
||||
assert {:ok, "Aladdin:open sesam"} == url_decode64("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding no pad" do
|
||||
assert "Aladdin:open sesam" == url_decode64!("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding incorrect padding" do
|
||||
assert {:ok, "Hello World"} == url_decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding incorrect padding" do
|
||||
assert "Hello World" == url_decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 empty" do
|
||||
assert "" == encode32("")
|
||||
end
|
||||
@@ -244,6 +356,26 @@ defmodule BaseTest do
|
||||
assert "MZXW6YTB" == encode32("fooba")
|
||||
end
|
||||
|
||||
test "encode32 omit padding one pad" do
|
||||
assert "MZXW6YQ" == encode32("foob", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding three pads" do
|
||||
assert "MZXW6" == encode32("foo", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding four pads" do
|
||||
assert "MZXQ" == encode32("fo", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding six pads" do
|
||||
assert "MZXW6YTBOI" == encode32("foobar", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding no pads" do
|
||||
assert "MZXW6YTB" == encode32("fooba", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 lowercase" do
|
||||
assert "mzxw6ytb" == encode32("fooba", case: :lower)
|
||||
end
|
||||
@@ -342,6 +474,70 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "decode32 ignore padding one pad" do
|
||||
assert {:ok, "foob"} == decode32("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding one pad" do
|
||||
assert "foob" == decode32!("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding three pads" do
|
||||
assert {:ok, "foo"} == decode32("MZXW6", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding three pads" do
|
||||
assert "foo" == decode32!("MZXW6", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding four pads" do
|
||||
assert {:ok, "fo"} == decode32("MZXQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding four pads" do
|
||||
assert "fo" == decode32!("MZXQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding lowercase" do
|
||||
assert {:ok, "fo"} == decode32("mzxq", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding lowercase" do
|
||||
assert "fo" == decode32!("mzxq", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding mixed case" do
|
||||
assert {:ok, "fo"} == decode32("mZXq", case: :mixed, padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding mixed case" do
|
||||
assert "fo" == decode32!("mZXq", case: :mixed, padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding six pads" do
|
||||
assert {:ok, "foobar"} == decode32("MZXW6YTBOI", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding six pads" do
|
||||
assert "foobar" == decode32!("MZXW6YTBOI", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding no pads" do
|
||||
assert {:ok, "fooba"} == decode32("MZXW6YTB", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding no pads" do
|
||||
assert "fooba" == decode32!("MZXW6YTB", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding incorrect padding" do
|
||||
assert {:ok, "foob"} == decode32("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding incorrect padding" do
|
||||
"foob" = decode32!("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 empty" do
|
||||
assert "" == hex_encode32("")
|
||||
end
|
||||
@@ -367,6 +563,26 @@ defmodule BaseTest do
|
||||
assert "CPNMUOJ1" == hex_encode32("fooba")
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding one pad" do
|
||||
assert "CPNMUOG" == hex_encode32("foob", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding three pads" do
|
||||
assert "CPNMU" == hex_encode32("foo", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding four pads" do
|
||||
assert "CPNG" == hex_encode32("fo", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding six pads" do
|
||||
assert "CPNMUOJ1E8" == hex_encode32("foobar", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding no pads" do
|
||||
assert "CPNMUOJ1" == hex_encode32("fooba", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 lowercase" do
|
||||
assert "cpnmuoj1" == hex_encode32("fooba", case: :lower)
|
||||
end
|
||||
@@ -470,4 +686,68 @@ defmodule BaseTest do
|
||||
decode16!("012" <> <<0>>)
|
||||
end
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding one pad" do
|
||||
assert {:ok, "foob"} == hex_decode32("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding one pad" do
|
||||
assert "foob" == hex_decode32!("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding three pads" do
|
||||
assert {:ok, "foo"} == hex_decode32("CPNMU", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding three pads" do
|
||||
assert "foo" == hex_decode32!("CPNMU", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding four pads" do
|
||||
assert {:ok, "fo"} == hex_decode32("CPNG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding four pads" do
|
||||
assert "fo" == hex_decode32!("CPNG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding six pads" do
|
||||
assert {:ok, "foobar"} == hex_decode32("CPNMUOJ1E8", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding six pads" do
|
||||
assert "foobar" == hex_decode32!("CPNMUOJ1E8", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding no pads" do
|
||||
assert {:ok, "fooba"} == hex_decode32("CPNMUOJ1", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding no pads" do
|
||||
assert "fooba" == hex_decode32!("CPNMUOJ1", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding incorrect padding" do
|
||||
assert {:ok, "foob"} == hex_decode32("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding incorrect padding" do
|
||||
"foob" = hex_decode32!("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignoring padding lowercase" do
|
||||
assert {:ok, "fo"} == hex_decode32("cpng", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding lowercase" do
|
||||
assert "fo" == hex_decode32!("cpng", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding mixed case" do
|
||||
assert {:ok, "fo"} == hex_decode32("cPNg====", case: :mixed, padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding mixed case" do
|
||||
assert "fo" == hex_decode32!("cPNg", case: :mixed, padding: false)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -290,6 +290,8 @@ defmodule MacroTest do
|
||||
assert Macro.to_string(quote do: ~R"123") == ~s/~R"123"/
|
||||
assert Macro.to_string(quote do: ~R"123"u) == ~s/~R"123"u/
|
||||
assert Macro.to_string(quote do: ~R"\n123") == ~s/~R"\\\\n123"/
|
||||
|
||||
assert Macro.to_string(quote do: Foo.bar(<<>>, [])) == "Foo.bar(<<>>, [])"
|
||||
end
|
||||
|
||||
test "arrow to string" do
|
||||
@@ -387,6 +389,7 @@ defmodule MacroTest do
|
||||
assert Macro.to_string(quote do: &foo/0) == "&foo/0"
|
||||
assert Macro.to_string(quote do: &Foo.foo/0) == "&Foo.foo/0"
|
||||
assert Macro.to_string(quote do: & &1 + &2) == "&(&1 + &2)"
|
||||
assert Macro.to_string(quote do: & &1) == "&(&1)"
|
||||
end
|
||||
|
||||
test "containers to string" do
|
||||
@@ -422,7 +425,6 @@ defmodule MacroTest do
|
||||
assert Macro.to_string(quote do: !(foo > bar)) == "!(foo > bar)"
|
||||
assert Macro.to_string(quote do: @foo(bar)) == "@foo(bar)"
|
||||
assert Macro.to_string(quote do: identity(&1)) == "identity(&1)"
|
||||
assert Macro.to_string(quote do: identity(&foo)) == "identity(&foo)"
|
||||
end
|
||||
|
||||
test "access to string" do
|
||||
|
||||
@@ -144,6 +144,13 @@ defmodule ModuleTest do
|
||||
assert [3, 2, 1] = @other_attribute
|
||||
end
|
||||
|
||||
test "@compile autoload attribute" do
|
||||
defmodule NoAutoload do
|
||||
@compile {:autoload, false}
|
||||
end
|
||||
refute :code.is_loaded(NoAutoload)
|
||||
end
|
||||
|
||||
## Naming
|
||||
|
||||
test "concat" do
|
||||
|
||||
@@ -319,6 +319,17 @@ defmodule Protocol.ConsolidationTest do
|
||||
refute Protocol.consolidated?(Enumerable)
|
||||
end
|
||||
|
||||
test "consolidation prevents new implementations" do
|
||||
assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
|
||||
defimpl WithAny, for: Integer do
|
||||
def ok(_any), do: :ok
|
||||
end
|
||||
end) =~ ~r"warning: the .+WithAny protocol has already been consolidated"
|
||||
after
|
||||
:code.purge(WithAny.Atom)
|
||||
:code.delete(WithAny.Atom)
|
||||
end
|
||||
|
||||
test "consolidated implementations without any" do
|
||||
assert is_nil Sample.impl_for(:foo)
|
||||
assert is_nil Sample.impl_for(fn(x) -> x end)
|
||||
|
||||
@@ -33,8 +33,12 @@ defmodule StringTest do
|
||||
assert String.split("foo bar ") == ["foo", "bar"]
|
||||
assert String.split(" foo bar ") == ["foo", "bar"]
|
||||
assert String.split("foo\t\n\v\f\r\sbar\n") == ["foo", "bar"]
|
||||
assert String.split("foo" <> <<31>> <> "bar") == ["foo", "bar"]
|
||||
assert String.split("foo" <> <<194, 133>> <> "bar") == ["foo", "bar"]
|
||||
# information separators are not considered whitespace
|
||||
assert String.split("foo\u001Fbar") == ["foo\u001Fbar"]
|
||||
# no-break space is excluded
|
||||
assert String.split("foo\00A0bar") == ["foo\00A0bar"]
|
||||
assert String.split("foo\u202Fbar") == ["foo\u202Fbar"]
|
||||
|
||||
assert String.split("a,b,c", ",") == ["a", "b", "c"]
|
||||
assert String.split("a,b", ".") == ["a,b"]
|
||||
@@ -160,6 +164,17 @@ defmodule StringTest do
|
||||
assert String.capitalize("fin") == "Fin"
|
||||
end
|
||||
|
||||
test "replace_trailing" do
|
||||
assert String.replace_trailing(" abc aa", "a", "") == " abc "
|
||||
assert String.replace_trailing(" abc __", "_", "") == " abc "
|
||||
assert String.replace_trailing(" aaaaaaaaa", "a", "") == " "
|
||||
assert String.replace_trailing("aaaaaaaaaa", "a", "") == ""
|
||||
assert String.replace_trailing("]]]]]]]]]]", "]", "") == ""
|
||||
assert String.replace_trailing(" cat 猫猫", "猫", "") == " cat "
|
||||
assert String.replace_trailing("test", "t", "") == "tes"
|
||||
assert String.replace_trailing("t", "t", "") == ""
|
||||
end
|
||||
|
||||
test "rstrip" do
|
||||
assert String.rstrip("") == ""
|
||||
assert String.rstrip("1\n") == "1"
|
||||
@@ -168,11 +183,17 @@ defmodule StringTest do
|
||||
assert String.rstrip(" abc a") == " abc a"
|
||||
assert String.rstrip("a abc a\n\n") == "a abc a"
|
||||
assert String.rstrip("a abc a\t\n\v\f\r\s") == "a abc a"
|
||||
assert String.rstrip("a abc a " <> <<31>>) == "a abc a"
|
||||
assert String.rstrip("a abc a" <> <<194, 133>>) == "a abc a"
|
||||
assert String.rstrip(" abc aa", ?a) == " abc "
|
||||
assert String.rstrip(" abc __", ?_) == " abc "
|
||||
assert String.rstrip(" aaaaaaaaa", ?a) == " "
|
||||
assert String.rstrip("aaaaaaaaaa", ?a) == ""
|
||||
assert String.rstrip("]]]]]]]]]]", ?]) == ""
|
||||
assert String.rstrip(" cat 猫猫", ?猫) == " cat "
|
||||
# information separators are not whitespace
|
||||
assert String.rstrip("a abc a \u001F") == "a abc a \u001F"
|
||||
# no-break space
|
||||
assert String.rstrip("a abc a \u00A0") == "a abc a"
|
||||
end
|
||||
|
||||
test "lstrip" do
|
||||
@@ -181,10 +202,13 @@ defmodule StringTest do
|
||||
assert String.lstrip("a abc a") == "a abc a"
|
||||
assert String.lstrip("\n\na abc a") == "a abc a"
|
||||
assert String.lstrip("\t\n\v\f\r\sa abc a") == "a abc a"
|
||||
assert String.lstrip(<<31>> <> " a abc a") == "a abc a"
|
||||
assert String.lstrip(<<194, 133>> <> "a abc a") == "a abc a"
|
||||
assert String.lstrip("__ abc _", ?_) == " abc _"
|
||||
assert String.lstrip("猫猫 cat ", ?猫) == " cat "
|
||||
# information separators are not whitespace
|
||||
assert String.lstrip("\u001F a abc a") == <<31>> <> " a abc a"
|
||||
# no-break space
|
||||
assert String.lstrip("\u00A0 a abc a") == "a abc a"
|
||||
end
|
||||
|
||||
test "strip" do
|
||||
@@ -194,6 +218,10 @@ defmodule StringTest do
|
||||
assert String.strip("a abc a\t\n\v\f\r\s") == "a abc a"
|
||||
assert String.strip("___ abc ___", ?_) == " abc "
|
||||
assert String.strip("猫猫猫 cat 猫猫猫", ?猫) == " cat "
|
||||
# no-break space
|
||||
assert String.strip("\u00A0a abc a\u00A0") == "a abc a"
|
||||
# whitespace defined as a range
|
||||
assert String.strip("\u2008a abc a\u2005") == "a abc a"
|
||||
end
|
||||
|
||||
test "rjust" do
|
||||
@@ -285,12 +313,43 @@ defmodule StringTest do
|
||||
end
|
||||
|
||||
test "normalize" do
|
||||
assert String.normalize("ḇravô", :nfd) == "ḇravô"
|
||||
assert String.normalize("ŝ", :nfd) == "ŝ"
|
||||
assert String.normalize("ḇravô", :nfd) == "ḇravô"
|
||||
assert String.normalize("ṩierra", :nfd) == "ṩierra"
|
||||
assert String.normalize("뢴", :nfd) == "뢴"
|
||||
assert String.normalize("êchǭ", :nfc) == "êchǭ"
|
||||
assert String.normalize("거̄", :nfc) == "거̄"
|
||||
assert String.normalize("뢴", :nfc) == "뢴"
|
||||
|
||||
## Cases from NormalizationTest.txt
|
||||
|
||||
# 05B8 05B9 05B1 0591 05C3 05B0 05AC 059F
|
||||
# 05B1 05B8 05B9 0591 05C3 05B0 05AC 059F
|
||||
# HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL,
|
||||
# HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,
|
||||
# HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA
|
||||
assert String.normalize("ֱָֹ֑׃ְ֬֟", :nfc) == "ֱָֹ֑׃ְ֬֟"
|
||||
|
||||
# 095D (exclusion list)
|
||||
# 0922 093C
|
||||
# DEVANAGARI LETTER RHA
|
||||
assert String.normalize("ढ़", :nfc) == "ढ़"
|
||||
|
||||
# 0061 0315 0300 05AE 0340 0062
|
||||
# 00E0 05AE 0300 0315 0062
|
||||
# LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT,
|
||||
# HEBREW ACCENT ZINOR, COMBINING GRAVE TONE MARK, LATIN SMALL LETTER B
|
||||
assert String.normalize("à֮̀̕b", :nfc) == "à֮̀̕b"
|
||||
|
||||
# 0344
|
||||
# 0308 0301
|
||||
# COMBINING GREEK DIALYTIKA TONOS
|
||||
assert String.normalize("\u0344", :nfc) == "\u0308\u0301"
|
||||
|
||||
# 115B9 0334 115AF
|
||||
# 115B9 0334 115AF
|
||||
# SIDDHAM VOWEL SIGN AI, COMBINING TILDE OVERLAY, SIDDHAM VOWEL SIGN AA
|
||||
assert String.normalize("𑖹̴𑖯", :nfc) == "𑖹̴𑖯"
|
||||
end
|
||||
|
||||
test "graphemes" do
|
||||
|
||||
@@ -60,6 +60,7 @@ defmodule VersionTest do
|
||||
test "parse" do
|
||||
assert {:ok, %V{major: 1, minor: 2, patch: 3}} = V.parse("1.2.3")
|
||||
assert {:ok, %V{major: 1, minor: 4, patch: 5}} = V.parse("1.4.5+ignore")
|
||||
assert {:ok, %V{major: 0, minor: 0, patch: 1}} = V.parse("0.0.1+sha.0702245")
|
||||
assert {:ok, %V{major: 1, minor: 4, patch: 5, pre: ["6-g3318bd5"]}} = V.parse("1.4.5-6-g3318bd5")
|
||||
assert {:ok, %V{major: 1, minor: 4, patch: 5, pre: [6, 7, "eight"]}} = V.parse("1.4.5-6.7.eight")
|
||||
assert {:ok, %V{major: 1, minor: 4, patch: 5, pre: ["6-g3318bd5"]}} = V.parse("1.4.5-6-g3318bd5+ignore")
|
||||
|
||||
@@ -1,745 +0,0 @@
|
||||
0300;230;
|
||||
0301;230;
|
||||
0302;230;
|
||||
0303;230;
|
||||
0304;230;
|
||||
0305;230;
|
||||
0306;230;
|
||||
0307;230;
|
||||
0308;230;
|
||||
0309;230;
|
||||
030A;230;
|
||||
030B;230;
|
||||
030C;230;
|
||||
030D;230;
|
||||
030E;230;
|
||||
030F;230;
|
||||
0310;230;
|
||||
0311;230;
|
||||
0312;230;
|
||||
0313;230;
|
||||
0314;230;
|
||||
0315;232;
|
||||
0316;220;
|
||||
0317;220;
|
||||
0318;220;
|
||||
0319;220;
|
||||
031A;232;
|
||||
031B;216;
|
||||
031C;220;
|
||||
031D;220;
|
||||
031E;220;
|
||||
031F;220;
|
||||
0320;220;
|
||||
0321;202;
|
||||
0322;202;
|
||||
0323;220;
|
||||
0324;220;
|
||||
0325;220;
|
||||
0326;220;
|
||||
0327;202;
|
||||
0328;202;
|
||||
0329;220;
|
||||
032A;220;
|
||||
032B;220;
|
||||
032C;220;
|
||||
032D;220;
|
||||
032E;220;
|
||||
032F;220;
|
||||
0330;220;
|
||||
0331;220;
|
||||
0332;220;
|
||||
0333;220;
|
||||
0334;1;
|
||||
0335;1;
|
||||
0336;1;
|
||||
0337;1;
|
||||
0338;1;
|
||||
0339;220;
|
||||
033A;220;
|
||||
033B;220;
|
||||
033C;220;
|
||||
033D;230;
|
||||
033E;230;
|
||||
033F;230;
|
||||
0340;230;
|
||||
0341;230;
|
||||
0342;230;
|
||||
0343;230;
|
||||
0344;230;
|
||||
0345;240;
|
||||
0346;230;
|
||||
0347;220;
|
||||
0348;220;
|
||||
0349;220;
|
||||
034A;230;
|
||||
034B;230;
|
||||
034C;230;
|
||||
034D;220;
|
||||
034E;220;
|
||||
0350;230;
|
||||
0351;230;
|
||||
0352;230;
|
||||
0353;220;
|
||||
0354;220;
|
||||
0355;220;
|
||||
0356;220;
|
||||
0357;230;
|
||||
0358;232;
|
||||
0359;220;
|
||||
035A;220;
|
||||
035B;230;
|
||||
035C;233;
|
||||
035D;234;
|
||||
035E;234;
|
||||
035F;233;
|
||||
0360;234;
|
||||
0361;234;
|
||||
0362;233;
|
||||
0363;230;
|
||||
0364;230;
|
||||
0365;230;
|
||||
0366;230;
|
||||
0367;230;
|
||||
0368;230;
|
||||
0369;230;
|
||||
036A;230;
|
||||
036B;230;
|
||||
036C;230;
|
||||
036D;230;
|
||||
036E;230;
|
||||
036F;230;
|
||||
0483;230;
|
||||
0484;230;
|
||||
0485;230;
|
||||
0486;230;
|
||||
0487;230;
|
||||
0591;220;
|
||||
0592;230;
|
||||
0593;230;
|
||||
0594;230;
|
||||
0595;230;
|
||||
0596;220;
|
||||
0597;230;
|
||||
0598;230;
|
||||
0599;230;
|
||||
059A;222;
|
||||
059B;220;
|
||||
059C;230;
|
||||
059D;230;
|
||||
059E;230;
|
||||
059F;230;
|
||||
05A0;230;
|
||||
05A1;230;
|
||||
05A2;220;
|
||||
05A3;220;
|
||||
05A4;220;
|
||||
05A5;220;
|
||||
05A6;220;
|
||||
05A7;220;
|
||||
05A8;230;
|
||||
05A9;230;
|
||||
05AA;220;
|
||||
05AB;230;
|
||||
05AC;230;
|
||||
05AD;222;
|
||||
05AE;228;
|
||||
05AF;230;
|
||||
05B0;10;
|
||||
05B1;11;
|
||||
05B2;12;
|
||||
05B3;13;
|
||||
05B4;14;
|
||||
05B5;15;
|
||||
05B6;16;
|
||||
05B7;17;
|
||||
05B8;18;
|
||||
05B9;19;
|
||||
05BA;19;
|
||||
05BB;20;
|
||||
05BC;21;
|
||||
05BD;22;
|
||||
05BF;23;
|
||||
05C1;24;
|
||||
05C2;25;
|
||||
05C4;230;
|
||||
05C5;220;
|
||||
05C7;18;
|
||||
0610;230;
|
||||
0611;230;
|
||||
0612;230;
|
||||
0613;230;
|
||||
0614;230;
|
||||
0615;230;
|
||||
0616;230;
|
||||
0617;230;
|
||||
0618;30;
|
||||
0619;31;
|
||||
061A;32;
|
||||
064B;27;
|
||||
064C;28;
|
||||
064D;29;
|
||||
064E;30;
|
||||
064F;31;
|
||||
0650;32;
|
||||
0651;33;
|
||||
0652;34;
|
||||
0653;230;
|
||||
0654;230;
|
||||
0655;220;
|
||||
0656;220;
|
||||
0657;230;
|
||||
0658;230;
|
||||
0659;230;
|
||||
065A;230;
|
||||
065B;230;
|
||||
065C;220;
|
||||
065D;230;
|
||||
065E;230;
|
||||
065F;220;
|
||||
0670;35;
|
||||
06D6;230;
|
||||
06D7;230;
|
||||
06D8;230;
|
||||
06D9;230;
|
||||
06DA;230;
|
||||
06DB;230;
|
||||
06DC;230;
|
||||
06DF;230;
|
||||
06E0;230;
|
||||
06E1;230;
|
||||
06E2;230;
|
||||
06E3;220;
|
||||
06E4;230;
|
||||
06E7;230;
|
||||
06E8;230;
|
||||
06EA;220;
|
||||
06EB;230;
|
||||
06EC;230;
|
||||
06ED;220;
|
||||
0711;36;
|
||||
0730;230;
|
||||
0731;220;
|
||||
0732;230;
|
||||
0733;230;
|
||||
0734;220;
|
||||
0735;230;
|
||||
0736;230;
|
||||
0737;220;
|
||||
0738;220;
|
||||
0739;220;
|
||||
073A;230;
|
||||
073B;220;
|
||||
073C;220;
|
||||
073D;230;
|
||||
073E;220;
|
||||
073F;230;
|
||||
0740;230;
|
||||
0741;230;
|
||||
0742;220;
|
||||
0743;230;
|
||||
0744;220;
|
||||
0745;230;
|
||||
0746;220;
|
||||
0747;230;
|
||||
0748;220;
|
||||
0749;230;
|
||||
074A;230;
|
||||
07EB;230;
|
||||
07EC;230;
|
||||
07ED;230;
|
||||
07EE;230;
|
||||
07EF;230;
|
||||
07F0;230;
|
||||
07F1;230;
|
||||
07F2;220;
|
||||
07F3;230;
|
||||
0816;230;
|
||||
0817;230;
|
||||
0818;230;
|
||||
0819;230;
|
||||
081B;230;
|
||||
081C;230;
|
||||
081D;230;
|
||||
081E;230;
|
||||
081F;230;
|
||||
0820;230;
|
||||
0821;230;
|
||||
0822;230;
|
||||
0823;230;
|
||||
0825;230;
|
||||
0826;230;
|
||||
0827;230;
|
||||
0829;230;
|
||||
082A;230;
|
||||
082B;230;
|
||||
082C;230;
|
||||
082D;230;
|
||||
0859;220;
|
||||
085A;220;
|
||||
085B;220;
|
||||
08E4;230;
|
||||
08E5;230;
|
||||
08E6;220;
|
||||
08E7;230;
|
||||
08E8;230;
|
||||
08E9;220;
|
||||
08EA;230;
|
||||
08EB;230;
|
||||
08EC;230;
|
||||
08ED;220;
|
||||
08EE;220;
|
||||
08EF;220;
|
||||
08F0;27;
|
||||
08F1;28;
|
||||
08F2;29;
|
||||
08F3;230;
|
||||
08F4;230;
|
||||
08F5;230;
|
||||
08F6;220;
|
||||
08F7;230;
|
||||
08F8;230;
|
||||
08F9;220;
|
||||
08FA;220;
|
||||
08FB;230;
|
||||
08FC;230;
|
||||
08FD;230;
|
||||
08FE;230;
|
||||
08FF;230;
|
||||
093C;7;
|
||||
094D;9;
|
||||
0951;230;
|
||||
0952;220;
|
||||
0953;230;
|
||||
0954;230;
|
||||
09BC;7;
|
||||
09CD;9;
|
||||
0A3C;7;
|
||||
0A4D;9;
|
||||
0ABC;7;
|
||||
0ACD;9;
|
||||
0B3C;7;
|
||||
0B4D;9;
|
||||
0BCD;9;
|
||||
0C4D;9;
|
||||
0C55;84;
|
||||
0C56;91;
|
||||
0CBC;7;
|
||||
0CCD;9;
|
||||
0D4D;9;
|
||||
0DCA;9;
|
||||
0E38;103;
|
||||
0E39;103;
|
||||
0E3A;9;
|
||||
0E48;107;
|
||||
0E49;107;
|
||||
0E4A;107;
|
||||
0E4B;107;
|
||||
0EB8;118;
|
||||
0EB9;118;
|
||||
0EC8;122;
|
||||
0EC9;122;
|
||||
0ECA;122;
|
||||
0ECB;122;
|
||||
0F18;220;
|
||||
0F19;220;
|
||||
0F35;220;
|
||||
0F37;220;
|
||||
0F39;216;
|
||||
0F71;129;
|
||||
0F72;130;
|
||||
0F74;132;
|
||||
0F7A;130;
|
||||
0F7B;130;
|
||||
0F7C;130;
|
||||
0F7D;130;
|
||||
0F80;130;
|
||||
0F82;230;
|
||||
0F83;230;
|
||||
0F84;9;
|
||||
0F86;230;
|
||||
0F87;230;
|
||||
0FC6;220;
|
||||
1037;7;
|
||||
1039;9;
|
||||
103A;9;
|
||||
108D;220;
|
||||
135D;230;
|
||||
135E;230;
|
||||
135F;230;
|
||||
1714;9;
|
||||
1734;9;
|
||||
17D2;9;
|
||||
17DD;230;
|
||||
18A9;228;
|
||||
1939;222;
|
||||
193A;230;
|
||||
193B;220;
|
||||
1A17;230;
|
||||
1A18;220;
|
||||
1A60;9;
|
||||
1A75;230;
|
||||
1A76;230;
|
||||
1A77;230;
|
||||
1A78;230;
|
||||
1A79;230;
|
||||
1A7A;230;
|
||||
1A7B;230;
|
||||
1A7C;230;
|
||||
1A7F;220;
|
||||
1AB0;230;
|
||||
1AB1;230;
|
||||
1AB2;230;
|
||||
1AB3;230;
|
||||
1AB4;230;
|
||||
1AB5;220;
|
||||
1AB6;220;
|
||||
1AB7;220;
|
||||
1AB8;220;
|
||||
1AB9;220;
|
||||
1ABA;220;
|
||||
1ABB;230;
|
||||
1ABC;230;
|
||||
1ABD;220;
|
||||
1B34;7;
|
||||
1B44;9;
|
||||
1B6B;230;
|
||||
1B6C;220;
|
||||
1B6D;230;
|
||||
1B6E;230;
|
||||
1B6F;230;
|
||||
1B70;230;
|
||||
1B71;230;
|
||||
1B72;230;
|
||||
1B73;230;
|
||||
1BAA;9;
|
||||
1BAB;9;
|
||||
1BE6;7;
|
||||
1BF2;9;
|
||||
1BF3;9;
|
||||
1C37;7;
|
||||
1CD0;230;
|
||||
1CD1;230;
|
||||
1CD2;230;
|
||||
1CD4;1;
|
||||
1CD5;220;
|
||||
1CD6;220;
|
||||
1CD7;220;
|
||||
1CD8;220;
|
||||
1CD9;220;
|
||||
1CDA;230;
|
||||
1CDB;230;
|
||||
1CDC;220;
|
||||
1CDD;220;
|
||||
1CDE;220;
|
||||
1CDF;220;
|
||||
1CE0;230;
|
||||
1CE2;1;
|
||||
1CE3;1;
|
||||
1CE4;1;
|
||||
1CE5;1;
|
||||
1CE6;1;
|
||||
1CE7;1;
|
||||
1CE8;1;
|
||||
1CED;220;
|
||||
1CF4;230;
|
||||
1CF8;230;
|
||||
1CF9;230;
|
||||
1DC0;230;
|
||||
1DC1;230;
|
||||
1DC2;220;
|
||||
1DC3;230;
|
||||
1DC4;230;
|
||||
1DC5;230;
|
||||
1DC6;230;
|
||||
1DC7;230;
|
||||
1DC8;230;
|
||||
1DC9;230;
|
||||
1DCA;220;
|
||||
1DCB;230;
|
||||
1DCC;230;
|
||||
1DCD;234;
|
||||
1DCE;214;
|
||||
1DCF;220;
|
||||
1DD0;202;
|
||||
1DD1;230;
|
||||
1DD2;230;
|
||||
1DD3;230;
|
||||
1DD4;230;
|
||||
1DD5;230;
|
||||
1DD6;230;
|
||||
1DD7;230;
|
||||
1DD8;230;
|
||||
1DD9;230;
|
||||
1DDA;230;
|
||||
1DDB;230;
|
||||
1DDC;230;
|
||||
1DDD;230;
|
||||
1DDE;230;
|
||||
1DDF;230;
|
||||
1DE0;230;
|
||||
1DE1;230;
|
||||
1DE2;230;
|
||||
1DE3;230;
|
||||
1DE4;230;
|
||||
1DE5;230;
|
||||
1DE6;230;
|
||||
1DE7;230;
|
||||
1DE8;230;
|
||||
1DE9;230;
|
||||
1DEA;230;
|
||||
1DEB;230;
|
||||
1DEC;230;
|
||||
1DED;230;
|
||||
1DEE;230;
|
||||
1DEF;230;
|
||||
1DF0;230;
|
||||
1DF1;230;
|
||||
1DF2;230;
|
||||
1DF3;230;
|
||||
1DF4;230;
|
||||
1DF5;230;
|
||||
1DFC;233;
|
||||
1DFD;220;
|
||||
1DFE;230;
|
||||
1DFF;220;
|
||||
20D0;230;
|
||||
20D1;230;
|
||||
20D2;1;
|
||||
20D3;1;
|
||||
20D4;230;
|
||||
20D5;230;
|
||||
20D6;230;
|
||||
20D7;230;
|
||||
20D8;1;
|
||||
20D9;1;
|
||||
20DA;1;
|
||||
20DB;230;
|
||||
20DC;230;
|
||||
20E1;230;
|
||||
20E5;1;
|
||||
20E6;1;
|
||||
20E7;230;
|
||||
20E8;220;
|
||||
20E9;230;
|
||||
20EA;1;
|
||||
20EB;1;
|
||||
20EC;220;
|
||||
20ED;220;
|
||||
20EE;220;
|
||||
20EF;220;
|
||||
20F0;230;
|
||||
2CEF;230;
|
||||
2CF0;230;
|
||||
2CF1;230;
|
||||
2D7F;9;
|
||||
2DE0;230;
|
||||
2DE1;230;
|
||||
2DE2;230;
|
||||
2DE3;230;
|
||||
2DE4;230;
|
||||
2DE5;230;
|
||||
2DE6;230;
|
||||
2DE7;230;
|
||||
2DE8;230;
|
||||
2DE9;230;
|
||||
2DEA;230;
|
||||
2DEB;230;
|
||||
2DEC;230;
|
||||
2DED;230;
|
||||
2DEE;230;
|
||||
2DEF;230;
|
||||
2DF0;230;
|
||||
2DF1;230;
|
||||
2DF2;230;
|
||||
2DF3;230;
|
||||
2DF4;230;
|
||||
2DF5;230;
|
||||
2DF6;230;
|
||||
2DF7;230;
|
||||
2DF8;230;
|
||||
2DF9;230;
|
||||
2DFA;230;
|
||||
2DFB;230;
|
||||
2DFC;230;
|
||||
2DFD;230;
|
||||
2DFE;230;
|
||||
2DFF;230;
|
||||
302A;218;
|
||||
302B;228;
|
||||
302C;232;
|
||||
302D;222;
|
||||
302E;224;
|
||||
302F;224;
|
||||
3099;8;
|
||||
309A;8;
|
||||
A66F;230;
|
||||
A674;230;
|
||||
A675;230;
|
||||
A676;230;
|
||||
A677;230;
|
||||
A678;230;
|
||||
A679;230;
|
||||
A67A;230;
|
||||
A67B;230;
|
||||
A67C;230;
|
||||
A67D;230;
|
||||
A69F;230;
|
||||
A6F0;230;
|
||||
A6F1;230;
|
||||
A806;9;
|
||||
A8C4;9;
|
||||
A8E0;230;
|
||||
A8E1;230;
|
||||
A8E2;230;
|
||||
A8E3;230;
|
||||
A8E4;230;
|
||||
A8E5;230;
|
||||
A8E6;230;
|
||||
A8E7;230;
|
||||
A8E8;230;
|
||||
A8E9;230;
|
||||
A8EA;230;
|
||||
A8EB;230;
|
||||
A8EC;230;
|
||||
A8ED;230;
|
||||
A8EE;230;
|
||||
A8EF;230;
|
||||
A8F0;230;
|
||||
A8F1;230;
|
||||
A92B;220;
|
||||
A92C;220;
|
||||
A92D;220;
|
||||
A953;9;
|
||||
A9B3;7;
|
||||
A9C0;9;
|
||||
AAB0;230;
|
||||
AAB2;230;
|
||||
AAB3;230;
|
||||
AAB4;220;
|
||||
AAB7;230;
|
||||
AAB8;230;
|
||||
AABE;230;
|
||||
AABF;230;
|
||||
AAC1;230;
|
||||
AAF6;9;
|
||||
ABED;9;
|
||||
FB1E;26;
|
||||
FE20;230;
|
||||
FE21;230;
|
||||
FE22;230;
|
||||
FE23;230;
|
||||
FE24;230;
|
||||
FE25;230;
|
||||
FE26;230;
|
||||
FE27;220;
|
||||
FE28;220;
|
||||
FE29;220;
|
||||
FE2A;220;
|
||||
FE2B;220;
|
||||
FE2C;220;
|
||||
FE2D;220;
|
||||
101FD;220;
|
||||
102E0;220;
|
||||
10376;230;
|
||||
10377;230;
|
||||
10378;230;
|
||||
10379;230;
|
||||
1037A;230;
|
||||
10A0D;220;
|
||||
10A0F;230;
|
||||
10A38;230;
|
||||
10A39;1;
|
||||
10A3A;220;
|
||||
10A3F;9;
|
||||
10AE5;230;
|
||||
10AE6;220;
|
||||
11046;9;
|
||||
1107F;9;
|
||||
110B9;9;
|
||||
110BA;7;
|
||||
11100;230;
|
||||
11101;230;
|
||||
11102;230;
|
||||
11133;9;
|
||||
11134;9;
|
||||
11173;7;
|
||||
111C0;9;
|
||||
11235;9;
|
||||
11236;7;
|
||||
112E9;7;
|
||||
112EA;9;
|
||||
1133C;7;
|
||||
1134D;9;
|
||||
11366;230;
|
||||
11367;230;
|
||||
11368;230;
|
||||
11369;230;
|
||||
1136A;230;
|
||||
1136B;230;
|
||||
1136C;230;
|
||||
11370;230;
|
||||
11371;230;
|
||||
11372;230;
|
||||
11373;230;
|
||||
11374;230;
|
||||
114C2;9;
|
||||
114C3;7;
|
||||
115BF;9;
|
||||
115C0;7;
|
||||
1163F;9;
|
||||
116B6;9;
|
||||
116B7;7;
|
||||
16AF0;1;
|
||||
16AF1;1;
|
||||
16AF2;1;
|
||||
16AF3;1;
|
||||
16AF4;1;
|
||||
16B30;230;
|
||||
16B31;230;
|
||||
16B32;230;
|
||||
16B33;230;
|
||||
16B34;230;
|
||||
16B35;230;
|
||||
16B36;230;
|
||||
1BC9E;1;
|
||||
1D165;216;
|
||||
1D166;216;
|
||||
1D167;1;
|
||||
1D168;1;
|
||||
1D169;1;
|
||||
1D16D;226;
|
||||
1D16E;216;
|
||||
1D16F;216;
|
||||
1D170;216;
|
||||
1D171;216;
|
||||
1D172;216;
|
||||
1D17B;220;
|
||||
1D17C;220;
|
||||
1D17D;220;
|
||||
1D17E;220;
|
||||
1D17F;220;
|
||||
1D180;220;
|
||||
1D181;220;
|
||||
1D182;220;
|
||||
1D185;230;
|
||||
1D186;230;
|
||||
1D187;230;
|
||||
1D188;230;
|
||||
1D189;230;
|
||||
1D18A;220;
|
||||
1D18B;220;
|
||||
1D1AA;230;
|
||||
1D1AB;230;
|
||||
1D1AC;230;
|
||||
1D1AD;230;
|
||||
1D242;230;
|
||||
1D243;230;
|
||||
1D244;230;
|
||||
1E8D0;220;
|
||||
1E8D1;220;
|
||||
1E8D2;220;
|
||||
1E8D3;220;
|
||||
1E8D4;220;
|
||||
1E8D5;220;
|
||||
1E8D6;220;
|
||||
@@ -1,940 +0,0 @@
|
||||
0041;0300;00C0;
|
||||
0041;0301;00C1;
|
||||
0041;0302;00C2;
|
||||
0041;0303;00C3;
|
||||
0041;0308;00C4;
|
||||
0041;030A;00C5;
|
||||
0043;0327;00C7;
|
||||
0045;0300;00C8;
|
||||
0045;0301;00C9;
|
||||
0045;0302;00CA;
|
||||
0045;0308;00CB;
|
||||
0049;0300;00CC;
|
||||
0049;0301;00CD;
|
||||
0049;0302;00CE;
|
||||
0049;0308;00CF;
|
||||
004E;0303;00D1;
|
||||
004F;0300;00D2;
|
||||
004F;0301;00D3;
|
||||
004F;0302;00D4;
|
||||
004F;0303;00D5;
|
||||
004F;0308;00D6;
|
||||
0055;0300;00D9;
|
||||
0055;0301;00DA;
|
||||
0055;0302;00DB;
|
||||
0055;0308;00DC;
|
||||
0059;0301;00DD;
|
||||
0061;0300;00E0;
|
||||
0061;0301;00E1;
|
||||
0061;0302;00E2;
|
||||
0061;0303;00E3;
|
||||
0061;0308;00E4;
|
||||
0061;030A;00E5;
|
||||
0063;0327;00E7;
|
||||
0065;0300;00E8;
|
||||
0065;0301;00E9;
|
||||
0065;0302;00EA;
|
||||
0065;0308;00EB;
|
||||
0069;0300;00EC;
|
||||
0069;0301;00ED;
|
||||
0069;0302;00EE;
|
||||
0069;0308;00EF;
|
||||
006E;0303;00F1;
|
||||
006F;0300;00F2;
|
||||
006F;0301;00F3;
|
||||
006F;0302;00F4;
|
||||
006F;0303;00F5;
|
||||
006F;0308;00F6;
|
||||
0075;0300;00F9;
|
||||
0075;0301;00FA;
|
||||
0075;0302;00FB;
|
||||
0075;0308;00FC;
|
||||
0079;0301;00FD;
|
||||
0079;0308;00FF;
|
||||
0041;0304;0100;
|
||||
0061;0304;0101;
|
||||
0041;0306;0102;
|
||||
0061;0306;0103;
|
||||
0041;0328;0104;
|
||||
0061;0328;0105;
|
||||
0043;0301;0106;
|
||||
0063;0301;0107;
|
||||
0043;0302;0108;
|
||||
0063;0302;0109;
|
||||
0043;0307;010A;
|
||||
0063;0307;010B;
|
||||
0043;030C;010C;
|
||||
0063;030C;010D;
|
||||
0044;030C;010E;
|
||||
0064;030C;010F;
|
||||
0045;0304;0112;
|
||||
0065;0304;0113;
|
||||
0045;0306;0114;
|
||||
0065;0306;0115;
|
||||
0045;0307;0116;
|
||||
0065;0307;0117;
|
||||
0045;0328;0118;
|
||||
0065;0328;0119;
|
||||
0045;030C;011A;
|
||||
0065;030C;011B;
|
||||
0047;0302;011C;
|
||||
0067;0302;011D;
|
||||
0047;0306;011E;
|
||||
0067;0306;011F;
|
||||
0047;0307;0120;
|
||||
0067;0307;0121;
|
||||
0047;0327;0122;
|
||||
0067;0327;0123;
|
||||
0048;0302;0124;
|
||||
0068;0302;0125;
|
||||
0049;0303;0128;
|
||||
0069;0303;0129;
|
||||
0049;0304;012A;
|
||||
0069;0304;012B;
|
||||
0049;0306;012C;
|
||||
0069;0306;012D;
|
||||
0049;0328;012E;
|
||||
0069;0328;012F;
|
||||
0049;0307;0130;
|
||||
004A;0302;0134;
|
||||
006A;0302;0135;
|
||||
004B;0327;0136;
|
||||
006B;0327;0137;
|
||||
004C;0301;0139;
|
||||
006C;0301;013A;
|
||||
004C;0327;013B;
|
||||
006C;0327;013C;
|
||||
004C;030C;013D;
|
||||
006C;030C;013E;
|
||||
004E;0301;0143;
|
||||
006E;0301;0144;
|
||||
004E;0327;0145;
|
||||
006E;0327;0146;
|
||||
004E;030C;0147;
|
||||
006E;030C;0148;
|
||||
004F;0304;014C;
|
||||
006F;0304;014D;
|
||||
004F;0306;014E;
|
||||
006F;0306;014F;
|
||||
004F;030B;0150;
|
||||
006F;030B;0151;
|
||||
0052;0301;0154;
|
||||
0072;0301;0155;
|
||||
0052;0327;0156;
|
||||
0072;0327;0157;
|
||||
0052;030C;0158;
|
||||
0072;030C;0159;
|
||||
0053;0301;015A;
|
||||
0073;0301;015B;
|
||||
0053;0302;015C;
|
||||
0073;0302;015D;
|
||||
0053;0327;015E;
|
||||
0073;0327;015F;
|
||||
0053;030C;0160;
|
||||
0073;030C;0161;
|
||||
0054;0327;0162;
|
||||
0074;0327;0163;
|
||||
0054;030C;0164;
|
||||
0074;030C;0165;
|
||||
0055;0303;0168;
|
||||
0075;0303;0169;
|
||||
0055;0304;016A;
|
||||
0075;0304;016B;
|
||||
0055;0306;016C;
|
||||
0075;0306;016D;
|
||||
0055;030A;016E;
|
||||
0075;030A;016F;
|
||||
0055;030B;0170;
|
||||
0075;030B;0171;
|
||||
0055;0328;0172;
|
||||
0075;0328;0173;
|
||||
0057;0302;0174;
|
||||
0077;0302;0175;
|
||||
0059;0302;0176;
|
||||
0079;0302;0177;
|
||||
0059;0308;0178;
|
||||
005A;0301;0179;
|
||||
007A;0301;017A;
|
||||
005A;0307;017B;
|
||||
007A;0307;017C;
|
||||
005A;030C;017D;
|
||||
007A;030C;017E;
|
||||
004F;031B;01A0;
|
||||
006F;031B;01A1;
|
||||
0055;031B;01AF;
|
||||
0075;031B;01B0;
|
||||
0041;030C;01CD;
|
||||
0061;030C;01CE;
|
||||
0049;030C;01CF;
|
||||
0069;030C;01D0;
|
||||
004F;030C;01D1;
|
||||
006F;030C;01D2;
|
||||
0055;030C;01D3;
|
||||
0075;030C;01D4;
|
||||
00DC;0304;01D5;
|
||||
00FC;0304;01D6;
|
||||
00DC;0301;01D7;
|
||||
00FC;0301;01D8;
|
||||
00DC;030C;01D9;
|
||||
00FC;030C;01DA;
|
||||
00DC;0300;01DB;
|
||||
00FC;0300;01DC;
|
||||
00C4;0304;01DE;
|
||||
00E4;0304;01DF;
|
||||
0226;0304;01E0;
|
||||
0227;0304;01E1;
|
||||
00C6;0304;01E2;
|
||||
00E6;0304;01E3;
|
||||
0047;030C;01E6;
|
||||
0067;030C;01E7;
|
||||
004B;030C;01E8;
|
||||
006B;030C;01E9;
|
||||
004F;0328;01EA;
|
||||
006F;0328;01EB;
|
||||
01EA;0304;01EC;
|
||||
01EB;0304;01ED;
|
||||
01B7;030C;01EE;
|
||||
0292;030C;01EF;
|
||||
006A;030C;01F0;
|
||||
0047;0301;01F4;
|
||||
0067;0301;01F5;
|
||||
004E;0300;01F8;
|
||||
006E;0300;01F9;
|
||||
00C5;0301;01FA;
|
||||
00E5;0301;01FB;
|
||||
00C6;0301;01FC;
|
||||
00E6;0301;01FD;
|
||||
00D8;0301;01FE;
|
||||
00F8;0301;01FF;
|
||||
0041;030F;0200;
|
||||
0061;030F;0201;
|
||||
0041;0311;0202;
|
||||
0061;0311;0203;
|
||||
0045;030F;0204;
|
||||
0065;030F;0205;
|
||||
0045;0311;0206;
|
||||
0065;0311;0207;
|
||||
0049;030F;0208;
|
||||
0069;030F;0209;
|
||||
0049;0311;020A;
|
||||
0069;0311;020B;
|
||||
004F;030F;020C;
|
||||
006F;030F;020D;
|
||||
004F;0311;020E;
|
||||
006F;0311;020F;
|
||||
0052;030F;0210;
|
||||
0072;030F;0211;
|
||||
0052;0311;0212;
|
||||
0072;0311;0213;
|
||||
0055;030F;0214;
|
||||
0075;030F;0215;
|
||||
0055;0311;0216;
|
||||
0075;0311;0217;
|
||||
0053;0326;0218;
|
||||
0073;0326;0219;
|
||||
0054;0326;021A;
|
||||
0074;0326;021B;
|
||||
0048;030C;021E;
|
||||
0068;030C;021F;
|
||||
0041;0307;0226;
|
||||
0061;0307;0227;
|
||||
0045;0327;0228;
|
||||
0065;0327;0229;
|
||||
00D6;0304;022A;
|
||||
00F6;0304;022B;
|
||||
00D5;0304;022C;
|
||||
00F5;0304;022D;
|
||||
004F;0307;022E;
|
||||
006F;0307;022F;
|
||||
022E;0304;0230;
|
||||
022F;0304;0231;
|
||||
0059;0304;0232;
|
||||
0079;0304;0233;
|
||||
00A8;0301;0385;
|
||||
0391;0301;0386;
|
||||
0395;0301;0388;
|
||||
0397;0301;0389;
|
||||
0399;0301;038A;
|
||||
039F;0301;038C;
|
||||
03A5;0301;038E;
|
||||
03A9;0301;038F;
|
||||
03CA;0301;0390;
|
||||
0399;0308;03AA;
|
||||
03A5;0308;03AB;
|
||||
03B1;0301;03AC;
|
||||
03B5;0301;03AD;
|
||||
03B7;0301;03AE;
|
||||
03B9;0301;03AF;
|
||||
03CB;0301;03B0;
|
||||
03B9;0308;03CA;
|
||||
03C5;0308;03CB;
|
||||
03BF;0301;03CC;
|
||||
03C5;0301;03CD;
|
||||
03C9;0301;03CE;
|
||||
03D2;0301;03D3;
|
||||
03D2;0308;03D4;
|
||||
0415;0300;0400;
|
||||
0415;0308;0401;
|
||||
0413;0301;0403;
|
||||
0406;0308;0407;
|
||||
041A;0301;040C;
|
||||
0418;0300;040D;
|
||||
0423;0306;040E;
|
||||
0418;0306;0419;
|
||||
0438;0306;0439;
|
||||
0435;0300;0450;
|
||||
0435;0308;0451;
|
||||
0433;0301;0453;
|
||||
0456;0308;0457;
|
||||
043A;0301;045C;
|
||||
0438;0300;045D;
|
||||
0443;0306;045E;
|
||||
0474;030F;0476;
|
||||
0475;030F;0477;
|
||||
0416;0306;04C1;
|
||||
0436;0306;04C2;
|
||||
0410;0306;04D0;
|
||||
0430;0306;04D1;
|
||||
0410;0308;04D2;
|
||||
0430;0308;04D3;
|
||||
0415;0306;04D6;
|
||||
0435;0306;04D7;
|
||||
04D8;0308;04DA;
|
||||
04D9;0308;04DB;
|
||||
0416;0308;04DC;
|
||||
0436;0308;04DD;
|
||||
0417;0308;04DE;
|
||||
0437;0308;04DF;
|
||||
0418;0304;04E2;
|
||||
0438;0304;04E3;
|
||||
0418;0308;04E4;
|
||||
0438;0308;04E5;
|
||||
041E;0308;04E6;
|
||||
043E;0308;04E7;
|
||||
04E8;0308;04EA;
|
||||
04E9;0308;04EB;
|
||||
042D;0308;04EC;
|
||||
044D;0308;04ED;
|
||||
0423;0304;04EE;
|
||||
0443;0304;04EF;
|
||||
0423;0308;04F0;
|
||||
0443;0308;04F1;
|
||||
0423;030B;04F2;
|
||||
0443;030B;04F3;
|
||||
0427;0308;04F4;
|
||||
0447;0308;04F5;
|
||||
042B;0308;04F8;
|
||||
044B;0308;04F9;
|
||||
0627;0653;0622;
|
||||
0627;0654;0623;
|
||||
0648;0654;0624;
|
||||
0627;0655;0625;
|
||||
064A;0654;0626;
|
||||
06D5;0654;06C0;
|
||||
06C1;0654;06C2;
|
||||
06D2;0654;06D3;
|
||||
0928;093C;0929;
|
||||
0930;093C;0931;
|
||||
0933;093C;0934;
|
||||
09C7;09BE;09CB;
|
||||
09C7;09D7;09CC;
|
||||
0B47;0B56;0B48;
|
||||
0B47;0B3E;0B4B;
|
||||
0B47;0B57;0B4C;
|
||||
0B92;0BD7;0B94;
|
||||
0BC6;0BBE;0BCA;
|
||||
0BC7;0BBE;0BCB;
|
||||
0BC6;0BD7;0BCC;
|
||||
0C46;0C56;0C48;
|
||||
0CBF;0CD5;0CC0;
|
||||
0CC6;0CD5;0CC7;
|
||||
0CC6;0CD6;0CC8;
|
||||
0CC6;0CC2;0CCA;
|
||||
0CCA;0CD5;0CCB;
|
||||
0D46;0D3E;0D4A;
|
||||
0D47;0D3E;0D4B;
|
||||
0D46;0D57;0D4C;
|
||||
0DD9;0DCA;0DDA;
|
||||
0DD9;0DCF;0DDC;
|
||||
0DDC;0DCA;0DDD;
|
||||
0DD9;0DDF;0DDE;
|
||||
1025;102E;1026;
|
||||
1B05;1B35;1B06;
|
||||
1B07;1B35;1B08;
|
||||
1B09;1B35;1B0A;
|
||||
1B0B;1B35;1B0C;
|
||||
1B0D;1B35;1B0E;
|
||||
1B11;1B35;1B12;
|
||||
1B3A;1B35;1B3B;
|
||||
1B3C;1B35;1B3D;
|
||||
1B3E;1B35;1B40;
|
||||
1B3F;1B35;1B41;
|
||||
1B42;1B35;1B43;
|
||||
0041;0325;1E00;
|
||||
0061;0325;1E01;
|
||||
0042;0307;1E02;
|
||||
0062;0307;1E03;
|
||||
0042;0323;1E04;
|
||||
0062;0323;1E05;
|
||||
0042;0331;1E06;
|
||||
0062;0331;1E07;
|
||||
00C7;0301;1E08;
|
||||
00E7;0301;1E09;
|
||||
0044;0307;1E0A;
|
||||
0064;0307;1E0B;
|
||||
0044;0323;1E0C;
|
||||
0064;0323;1E0D;
|
||||
0044;0331;1E0E;
|
||||
0064;0331;1E0F;
|
||||
0044;0327;1E10;
|
||||
0064;0327;1E11;
|
||||
0044;032D;1E12;
|
||||
0064;032D;1E13;
|
||||
0112;0300;1E14;
|
||||
0113;0300;1E15;
|
||||
0112;0301;1E16;
|
||||
0113;0301;1E17;
|
||||
0045;032D;1E18;
|
||||
0065;032D;1E19;
|
||||
0045;0330;1E1A;
|
||||
0065;0330;1E1B;
|
||||
0228;0306;1E1C;
|
||||
0229;0306;1E1D;
|
||||
0046;0307;1E1E;
|
||||
0066;0307;1E1F;
|
||||
0047;0304;1E20;
|
||||
0067;0304;1E21;
|
||||
0048;0307;1E22;
|
||||
0068;0307;1E23;
|
||||
0048;0323;1E24;
|
||||
0068;0323;1E25;
|
||||
0048;0308;1E26;
|
||||
0068;0308;1E27;
|
||||
0048;0327;1E28;
|
||||
0068;0327;1E29;
|
||||
0048;032E;1E2A;
|
||||
0068;032E;1E2B;
|
||||
0049;0330;1E2C;
|
||||
0069;0330;1E2D;
|
||||
00CF;0301;1E2E;
|
||||
00EF;0301;1E2F;
|
||||
004B;0301;1E30;
|
||||
006B;0301;1E31;
|
||||
004B;0323;1E32;
|
||||
006B;0323;1E33;
|
||||
004B;0331;1E34;
|
||||
006B;0331;1E35;
|
||||
004C;0323;1E36;
|
||||
006C;0323;1E37;
|
||||
1E36;0304;1E38;
|
||||
1E37;0304;1E39;
|
||||
004C;0331;1E3A;
|
||||
006C;0331;1E3B;
|
||||
004C;032D;1E3C;
|
||||
006C;032D;1E3D;
|
||||
004D;0301;1E3E;
|
||||
006D;0301;1E3F;
|
||||
004D;0307;1E40;
|
||||
006D;0307;1E41;
|
||||
004D;0323;1E42;
|
||||
006D;0323;1E43;
|
||||
004E;0307;1E44;
|
||||
006E;0307;1E45;
|
||||
004E;0323;1E46;
|
||||
006E;0323;1E47;
|
||||
004E;0331;1E48;
|
||||
006E;0331;1E49;
|
||||
004E;032D;1E4A;
|
||||
006E;032D;1E4B;
|
||||
00D5;0301;1E4C;
|
||||
00F5;0301;1E4D;
|
||||
00D5;0308;1E4E;
|
||||
00F5;0308;1E4F;
|
||||
014C;0300;1E50;
|
||||
014D;0300;1E51;
|
||||
014C;0301;1E52;
|
||||
014D;0301;1E53;
|
||||
0050;0301;1E54;
|
||||
0070;0301;1E55;
|
||||
0050;0307;1E56;
|
||||
0070;0307;1E57;
|
||||
0052;0307;1E58;
|
||||
0072;0307;1E59;
|
||||
0052;0323;1E5A;
|
||||
0072;0323;1E5B;
|
||||
1E5A;0304;1E5C;
|
||||
1E5B;0304;1E5D;
|
||||
0052;0331;1E5E;
|
||||
0072;0331;1E5F;
|
||||
0053;0307;1E60;
|
||||
0073;0307;1E61;
|
||||
0053;0323;1E62;
|
||||
0073;0323;1E63;
|
||||
015A;0307;1E64;
|
||||
015B;0307;1E65;
|
||||
0160;0307;1E66;
|
||||
0161;0307;1E67;
|
||||
1E62;0307;1E68;
|
||||
1E63;0307;1E69;
|
||||
0054;0307;1E6A;
|
||||
0074;0307;1E6B;
|
||||
0054;0323;1E6C;
|
||||
0074;0323;1E6D;
|
||||
0054;0331;1E6E;
|
||||
0074;0331;1E6F;
|
||||
0054;032D;1E70;
|
||||
0074;032D;1E71;
|
||||
0055;0324;1E72;
|
||||
0075;0324;1E73;
|
||||
0055;0330;1E74;
|
||||
0075;0330;1E75;
|
||||
0055;032D;1E76;
|
||||
0075;032D;1E77;
|
||||
0168;0301;1E78;
|
||||
0169;0301;1E79;
|
||||
016A;0308;1E7A;
|
||||
016B;0308;1E7B;
|
||||
0056;0303;1E7C;
|
||||
0076;0303;1E7D;
|
||||
0056;0323;1E7E;
|
||||
0076;0323;1E7F;
|
||||
0057;0300;1E80;
|
||||
0077;0300;1E81;
|
||||
0057;0301;1E82;
|
||||
0077;0301;1E83;
|
||||
0057;0308;1E84;
|
||||
0077;0308;1E85;
|
||||
0057;0307;1E86;
|
||||
0077;0307;1E87;
|
||||
0057;0323;1E88;
|
||||
0077;0323;1E89;
|
||||
0058;0307;1E8A;
|
||||
0078;0307;1E8B;
|
||||
0058;0308;1E8C;
|
||||
0078;0308;1E8D;
|
||||
0059;0307;1E8E;
|
||||
0079;0307;1E8F;
|
||||
005A;0302;1E90;
|
||||
007A;0302;1E91;
|
||||
005A;0323;1E92;
|
||||
007A;0323;1E93;
|
||||
005A;0331;1E94;
|
||||
007A;0331;1E95;
|
||||
0068;0331;1E96;
|
||||
0074;0308;1E97;
|
||||
0077;030A;1E98;
|
||||
0079;030A;1E99;
|
||||
017F;0307;1E9B;
|
||||
0041;0323;1EA0;
|
||||
0061;0323;1EA1;
|
||||
0041;0309;1EA2;
|
||||
0061;0309;1EA3;
|
||||
00C2;0301;1EA4;
|
||||
00E2;0301;1EA5;
|
||||
00C2;0300;1EA6;
|
||||
00E2;0300;1EA7;
|
||||
00C2;0309;1EA8;
|
||||
00E2;0309;1EA9;
|
||||
00C2;0303;1EAA;
|
||||
00E2;0303;1EAB;
|
||||
1EA0;0302;1EAC;
|
||||
1EA1;0302;1EAD;
|
||||
0102;0301;1EAE;
|
||||
0103;0301;1EAF;
|
||||
0102;0300;1EB0;
|
||||
0103;0300;1EB1;
|
||||
0102;0309;1EB2;
|
||||
0103;0309;1EB3;
|
||||
0102;0303;1EB4;
|
||||
0103;0303;1EB5;
|
||||
1EA0;0306;1EB6;
|
||||
1EA1;0306;1EB7;
|
||||
0045;0323;1EB8;
|
||||
0065;0323;1EB9;
|
||||
0045;0309;1EBA;
|
||||
0065;0309;1EBB;
|
||||
0045;0303;1EBC;
|
||||
0065;0303;1EBD;
|
||||
00CA;0301;1EBE;
|
||||
00EA;0301;1EBF;
|
||||
00CA;0300;1EC0;
|
||||
00EA;0300;1EC1;
|
||||
00CA;0309;1EC2;
|
||||
00EA;0309;1EC3;
|
||||
00CA;0303;1EC4;
|
||||
00EA;0303;1EC5;
|
||||
1EB8;0302;1EC6;
|
||||
1EB9;0302;1EC7;
|
||||
0049;0309;1EC8;
|
||||
0069;0309;1EC9;
|
||||
0049;0323;1ECA;
|
||||
0069;0323;1ECB;
|
||||
004F;0323;1ECC;
|
||||
006F;0323;1ECD;
|
||||
004F;0309;1ECE;
|
||||
006F;0309;1ECF;
|
||||
00D4;0301;1ED0;
|
||||
00F4;0301;1ED1;
|
||||
00D4;0300;1ED2;
|
||||
00F4;0300;1ED3;
|
||||
00D4;0309;1ED4;
|
||||
00F4;0309;1ED5;
|
||||
00D4;0303;1ED6;
|
||||
00F4;0303;1ED7;
|
||||
1ECC;0302;1ED8;
|
||||
1ECD;0302;1ED9;
|
||||
01A0;0301;1EDA;
|
||||
01A1;0301;1EDB;
|
||||
01A0;0300;1EDC;
|
||||
01A1;0300;1EDD;
|
||||
01A0;0309;1EDE;
|
||||
01A1;0309;1EDF;
|
||||
01A0;0303;1EE0;
|
||||
01A1;0303;1EE1;
|
||||
01A0;0323;1EE2;
|
||||
01A1;0323;1EE3;
|
||||
0055;0323;1EE4;
|
||||
0075;0323;1EE5;
|
||||
0055;0309;1EE6;
|
||||
0075;0309;1EE7;
|
||||
01AF;0301;1EE8;
|
||||
01B0;0301;1EE9;
|
||||
01AF;0300;1EEA;
|
||||
01B0;0300;1EEB;
|
||||
01AF;0309;1EEC;
|
||||
01B0;0309;1EED;
|
||||
01AF;0303;1EEE;
|
||||
01B0;0303;1EEF;
|
||||
01AF;0323;1EF0;
|
||||
01B0;0323;1EF1;
|
||||
0059;0300;1EF2;
|
||||
0079;0300;1EF3;
|
||||
0059;0323;1EF4;
|
||||
0079;0323;1EF5;
|
||||
0059;0309;1EF6;
|
||||
0079;0309;1EF7;
|
||||
0059;0303;1EF8;
|
||||
0079;0303;1EF9;
|
||||
03B1;0313;1F00;
|
||||
03B1;0314;1F01;
|
||||
1F00;0300;1F02;
|
||||
1F01;0300;1F03;
|
||||
1F00;0301;1F04;
|
||||
1F01;0301;1F05;
|
||||
1F00;0342;1F06;
|
||||
1F01;0342;1F07;
|
||||
0391;0313;1F08;
|
||||
0391;0314;1F09;
|
||||
1F08;0300;1F0A;
|
||||
1F09;0300;1F0B;
|
||||
1F08;0301;1F0C;
|
||||
1F09;0301;1F0D;
|
||||
1F08;0342;1F0E;
|
||||
1F09;0342;1F0F;
|
||||
03B5;0313;1F10;
|
||||
03B5;0314;1F11;
|
||||
1F10;0300;1F12;
|
||||
1F11;0300;1F13;
|
||||
1F10;0301;1F14;
|
||||
1F11;0301;1F15;
|
||||
0395;0313;1F18;
|
||||
0395;0314;1F19;
|
||||
1F18;0300;1F1A;
|
||||
1F19;0300;1F1B;
|
||||
1F18;0301;1F1C;
|
||||
1F19;0301;1F1D;
|
||||
03B7;0313;1F20;
|
||||
03B7;0314;1F21;
|
||||
1F20;0300;1F22;
|
||||
1F21;0300;1F23;
|
||||
1F20;0301;1F24;
|
||||
1F21;0301;1F25;
|
||||
1F20;0342;1F26;
|
||||
1F21;0342;1F27;
|
||||
0397;0313;1F28;
|
||||
0397;0314;1F29;
|
||||
1F28;0300;1F2A;
|
||||
1F29;0300;1F2B;
|
||||
1F28;0301;1F2C;
|
||||
1F29;0301;1F2D;
|
||||
1F28;0342;1F2E;
|
||||
1F29;0342;1F2F;
|
||||
03B9;0313;1F30;
|
||||
03B9;0314;1F31;
|
||||
1F30;0300;1F32;
|
||||
1F31;0300;1F33;
|
||||
1F30;0301;1F34;
|
||||
1F31;0301;1F35;
|
||||
1F30;0342;1F36;
|
||||
1F31;0342;1F37;
|
||||
0399;0313;1F38;
|
||||
0399;0314;1F39;
|
||||
1F38;0300;1F3A;
|
||||
1F39;0300;1F3B;
|
||||
1F38;0301;1F3C;
|
||||
1F39;0301;1F3D;
|
||||
1F38;0342;1F3E;
|
||||
1F39;0342;1F3F;
|
||||
03BF;0313;1F40;
|
||||
03BF;0314;1F41;
|
||||
1F40;0300;1F42;
|
||||
1F41;0300;1F43;
|
||||
1F40;0301;1F44;
|
||||
1F41;0301;1F45;
|
||||
039F;0313;1F48;
|
||||
039F;0314;1F49;
|
||||
1F48;0300;1F4A;
|
||||
1F49;0300;1F4B;
|
||||
1F48;0301;1F4C;
|
||||
1F49;0301;1F4D;
|
||||
03C5;0313;1F50;
|
||||
03C5;0314;1F51;
|
||||
1F50;0300;1F52;
|
||||
1F51;0300;1F53;
|
||||
1F50;0301;1F54;
|
||||
1F51;0301;1F55;
|
||||
1F50;0342;1F56;
|
||||
1F51;0342;1F57;
|
||||
03A5;0314;1F59;
|
||||
1F59;0300;1F5B;
|
||||
1F59;0301;1F5D;
|
||||
1F59;0342;1F5F;
|
||||
03C9;0313;1F60;
|
||||
03C9;0314;1F61;
|
||||
1F60;0300;1F62;
|
||||
1F61;0300;1F63;
|
||||
1F60;0301;1F64;
|
||||
1F61;0301;1F65;
|
||||
1F60;0342;1F66;
|
||||
1F61;0342;1F67;
|
||||
03A9;0313;1F68;
|
||||
03A9;0314;1F69;
|
||||
1F68;0300;1F6A;
|
||||
1F69;0300;1F6B;
|
||||
1F68;0301;1F6C;
|
||||
1F69;0301;1F6D;
|
||||
1F68;0342;1F6E;
|
||||
1F69;0342;1F6F;
|
||||
03B1;0300;1F70;
|
||||
03B5;0300;1F72;
|
||||
03B7;0300;1F74;
|
||||
03B9;0300;1F76;
|
||||
03BF;0300;1F78;
|
||||
03C5;0300;1F7A;
|
||||
03C9;0300;1F7C;
|
||||
1F00;0345;1F80;
|
||||
1F01;0345;1F81;
|
||||
1F02;0345;1F82;
|
||||
1F03;0345;1F83;
|
||||
1F04;0345;1F84;
|
||||
1F05;0345;1F85;
|
||||
1F06;0345;1F86;
|
||||
1F07;0345;1F87;
|
||||
1F08;0345;1F88;
|
||||
1F09;0345;1F89;
|
||||
1F0A;0345;1F8A;
|
||||
1F0B;0345;1F8B;
|
||||
1F0C;0345;1F8C;
|
||||
1F0D;0345;1F8D;
|
||||
1F0E;0345;1F8E;
|
||||
1F0F;0345;1F8F;
|
||||
1F20;0345;1F90;
|
||||
1F21;0345;1F91;
|
||||
1F22;0345;1F92;
|
||||
1F23;0345;1F93;
|
||||
1F24;0345;1F94;
|
||||
1F25;0345;1F95;
|
||||
1F26;0345;1F96;
|
||||
1F27;0345;1F97;
|
||||
1F28;0345;1F98;
|
||||
1F29;0345;1F99;
|
||||
1F2A;0345;1F9A;
|
||||
1F2B;0345;1F9B;
|
||||
1F2C;0345;1F9C;
|
||||
1F2D;0345;1F9D;
|
||||
1F2E;0345;1F9E;
|
||||
1F2F;0345;1F9F;
|
||||
1F60;0345;1FA0;
|
||||
1F61;0345;1FA1;
|
||||
1F62;0345;1FA2;
|
||||
1F63;0345;1FA3;
|
||||
1F64;0345;1FA4;
|
||||
1F65;0345;1FA5;
|
||||
1F66;0345;1FA6;
|
||||
1F67;0345;1FA7;
|
||||
1F68;0345;1FA8;
|
||||
1F69;0345;1FA9;
|
||||
1F6A;0345;1FAA;
|
||||
1F6B;0345;1FAB;
|
||||
1F6C;0345;1FAC;
|
||||
1F6D;0345;1FAD;
|
||||
1F6E;0345;1FAE;
|
||||
1F6F;0345;1FAF;
|
||||
03B1;0306;1FB0;
|
||||
03B1;0304;1FB1;
|
||||
1F70;0345;1FB2;
|
||||
03B1;0345;1FB3;
|
||||
03AC;0345;1FB4;
|
||||
03B1;0342;1FB6;
|
||||
1FB6;0345;1FB7;
|
||||
0391;0306;1FB8;
|
||||
0391;0304;1FB9;
|
||||
0391;0300;1FBA;
|
||||
0391;0345;1FBC;
|
||||
00A8;0342;1FC1;
|
||||
1F74;0345;1FC2;
|
||||
03B7;0345;1FC3;
|
||||
03AE;0345;1FC4;
|
||||
03B7;0342;1FC6;
|
||||
1FC6;0345;1FC7;
|
||||
0395;0300;1FC8;
|
||||
0397;0300;1FCA;
|
||||
0397;0345;1FCC;
|
||||
1FBF;0300;1FCD;
|
||||
1FBF;0301;1FCE;
|
||||
1FBF;0342;1FCF;
|
||||
03B9;0306;1FD0;
|
||||
03B9;0304;1FD1;
|
||||
03CA;0300;1FD2;
|
||||
03B9;0342;1FD6;
|
||||
03CA;0342;1FD7;
|
||||
0399;0306;1FD8;
|
||||
0399;0304;1FD9;
|
||||
0399;0300;1FDA;
|
||||
1FFE;0300;1FDD;
|
||||
1FFE;0301;1FDE;
|
||||
1FFE;0342;1FDF;
|
||||
03C5;0306;1FE0;
|
||||
03C5;0304;1FE1;
|
||||
03CB;0300;1FE2;
|
||||
03C1;0313;1FE4;
|
||||
03C1;0314;1FE5;
|
||||
03C5;0342;1FE6;
|
||||
03CB;0342;1FE7;
|
||||
03A5;0306;1FE8;
|
||||
03A5;0304;1FE9;
|
||||
03A5;0300;1FEA;
|
||||
03A1;0314;1FEC;
|
||||
00A8;0300;1FED;
|
||||
1F7C;0345;1FF2;
|
||||
03C9;0345;1FF3;
|
||||
03CE;0345;1FF4;
|
||||
03C9;0342;1FF6;
|
||||
1FF6;0345;1FF7;
|
||||
039F;0300;1FF8;
|
||||
03A9;0300;1FFA;
|
||||
03A9;0345;1FFC;
|
||||
2190;0338;219A;
|
||||
2192;0338;219B;
|
||||
2194;0338;21AE;
|
||||
21D0;0338;21CD;
|
||||
21D4;0338;21CE;
|
||||
21D2;0338;21CF;
|
||||
2203;0338;2204;
|
||||
2208;0338;2209;
|
||||
220B;0338;220C;
|
||||
2223;0338;2224;
|
||||
2225;0338;2226;
|
||||
223C;0338;2241;
|
||||
2243;0338;2244;
|
||||
2245;0338;2247;
|
||||
2248;0338;2249;
|
||||
003D;0338;2260;
|
||||
2261;0338;2262;
|
||||
224D;0338;226D;
|
||||
003C;0338;226E;
|
||||
003E;0338;226F;
|
||||
2264;0338;2270;
|
||||
2265;0338;2271;
|
||||
2272;0338;2274;
|
||||
2273;0338;2275;
|
||||
2276;0338;2278;
|
||||
2277;0338;2279;
|
||||
227A;0338;2280;
|
||||
227B;0338;2281;
|
||||
2282;0338;2284;
|
||||
2283;0338;2285;
|
||||
2286;0338;2288;
|
||||
2287;0338;2289;
|
||||
22A2;0338;22AC;
|
||||
22A8;0338;22AD;
|
||||
22A9;0338;22AE;
|
||||
22AB;0338;22AF;
|
||||
227C;0338;22E0;
|
||||
227D;0338;22E1;
|
||||
2291;0338;22E2;
|
||||
2292;0338;22E3;
|
||||
22B2;0338;22EA;
|
||||
22B3;0338;22EB;
|
||||
22B4;0338;22EC;
|
||||
22B5;0338;22ED;
|
||||
304B;3099;304C;
|
||||
304D;3099;304E;
|
||||
304F;3099;3050;
|
||||
3051;3099;3052;
|
||||
3053;3099;3054;
|
||||
3055;3099;3056;
|
||||
3057;3099;3058;
|
||||
3059;3099;305A;
|
||||
305B;3099;305C;
|
||||
305D;3099;305E;
|
||||
305F;3099;3060;
|
||||
3061;3099;3062;
|
||||
3064;3099;3065;
|
||||
3066;3099;3067;
|
||||
3068;3099;3069;
|
||||
306F;3099;3070;
|
||||
306F;309A;3071;
|
||||
3072;3099;3073;
|
||||
3072;309A;3074;
|
||||
3075;3099;3076;
|
||||
3075;309A;3077;
|
||||
3078;3099;3079;
|
||||
3078;309A;307A;
|
||||
307B;3099;307C;
|
||||
307B;309A;307D;
|
||||
3046;3099;3094;
|
||||
309D;3099;309E;
|
||||
30AB;3099;30AC;
|
||||
30AD;3099;30AE;
|
||||
30AF;3099;30B0;
|
||||
30B1;3099;30B2;
|
||||
30B3;3099;30B4;
|
||||
30B5;3099;30B6;
|
||||
30B7;3099;30B8;
|
||||
30B9;3099;30BA;
|
||||
30BB;3099;30BC;
|
||||
30BD;3099;30BE;
|
||||
30BF;3099;30C0;
|
||||
30C1;3099;30C2;
|
||||
30C4;3099;30C5;
|
||||
30C6;3099;30C7;
|
||||
30C8;3099;30C9;
|
||||
30CF;3099;30D0;
|
||||
30CF;309A;30D1;
|
||||
30D2;3099;30D3;
|
||||
30D2;309A;30D4;
|
||||
30D5;3099;30D6;
|
||||
30D5;309A;30D7;
|
||||
30D8;3099;30D9;
|
||||
30D8;309A;30DA;
|
||||
30DB;3099;30DC;
|
||||
30DB;309A;30DD;
|
||||
30A6;3099;30F4;
|
||||
30EF;3099;30F7;
|
||||
30F0;3099;30F8;
|
||||
30F1;3099;30F9;
|
||||
30F2;3099;30FA;
|
||||
30FD;3099;30FE;
|
||||
11099;110BA;1109A;
|
||||
1109B;110BA;1109C;
|
||||
110A5;110BA;110AB;
|
||||
11131;11127;1112E;
|
||||
11132;11127;1112F;
|
||||
11347;1133E;1134B;
|
||||
11347;11357;1134C;
|
||||
114B9;114BA;114BB;
|
||||
114B9;114B0;114BC;
|
||||
114B9;114BD;114BE;
|
||||
115B8;115AF;115BA;
|
||||
115B9;115AF;115BB;
|
||||
@@ -0,0 +1,206 @@
|
||||
# CompositionExclusions-8.0.0.txt
|
||||
# Date: 2015-02-19, 00:30:00 GMT [KW, LI]
|
||||
#
|
||||
# This file lists the characters for the Composition Exclusion Table
|
||||
# defined in UAX #15, Unicode Normalization Forms.
|
||||
#
|
||||
# This file is a normative contributory data file in the
|
||||
# Unicode Character Database.
|
||||
#
|
||||
# Copyright (c) 1991-2015 Unicode, Inc.
|
||||
# For terms of use, see http://www.unicode.org/terms_of_use.html
|
||||
#
|
||||
# For more information, see
|
||||
# http://www.unicode.org/unicode/reports/tr15/#Primary_Exclusion_List_Table
|
||||
#
|
||||
# For a full derivation of composition exclusions, see the derived property
|
||||
# Full_Composition_Exclusion in DerivedNormalizationProps.txt
|
||||
#
|
||||
|
||||
# ================================================
|
||||
# (1) Script Specifics
|
||||
#
|
||||
# This list of characters cannot be derived from the UnicodeData.txt file.
|
||||
# ================================================
|
||||
|
||||
0958 # DEVANAGARI LETTER QA
|
||||
0959 # DEVANAGARI LETTER KHHA
|
||||
095A # DEVANAGARI LETTER GHHA
|
||||
095B # DEVANAGARI LETTER ZA
|
||||
095C # DEVANAGARI LETTER DDDHA
|
||||
095D # DEVANAGARI LETTER RHA
|
||||
095E # DEVANAGARI LETTER FA
|
||||
095F # DEVANAGARI LETTER YYA
|
||||
09DC # BENGALI LETTER RRA
|
||||
09DD # BENGALI LETTER RHA
|
||||
09DF # BENGALI LETTER YYA
|
||||
0A33 # GURMUKHI LETTER LLA
|
||||
0A36 # GURMUKHI LETTER SHA
|
||||
0A59 # GURMUKHI LETTER KHHA
|
||||
0A5A # GURMUKHI LETTER GHHA
|
||||
0A5B # GURMUKHI LETTER ZA
|
||||
0A5E # GURMUKHI LETTER FA
|
||||
0B5C # ORIYA LETTER RRA
|
||||
0B5D # ORIYA LETTER RHA
|
||||
0F43 # TIBETAN LETTER GHA
|
||||
0F4D # TIBETAN LETTER DDHA
|
||||
0F52 # TIBETAN LETTER DHA
|
||||
0F57 # TIBETAN LETTER BHA
|
||||
0F5C # TIBETAN LETTER DZHA
|
||||
0F69 # TIBETAN LETTER KSSA
|
||||
0F76 # TIBETAN VOWEL SIGN VOCALIC R
|
||||
0F78 # TIBETAN VOWEL SIGN VOCALIC L
|
||||
0F93 # TIBETAN SUBJOINED LETTER GHA
|
||||
0F9D # TIBETAN SUBJOINED LETTER DDHA
|
||||
0FA2 # TIBETAN SUBJOINED LETTER DHA
|
||||
0FA7 # TIBETAN SUBJOINED LETTER BHA
|
||||
0FAC # TIBETAN SUBJOINED LETTER DZHA
|
||||
0FB9 # TIBETAN SUBJOINED LETTER KSSA
|
||||
FB1D # HEBREW LETTER YOD WITH HIRIQ
|
||||
FB1F # HEBREW LIGATURE YIDDISH YOD YOD PATAH
|
||||
FB2A # HEBREW LETTER SHIN WITH SHIN DOT
|
||||
FB2B # HEBREW LETTER SHIN WITH SIN DOT
|
||||
FB2C # HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT
|
||||
FB2D # HEBREW LETTER SHIN WITH DAGESH AND SIN DOT
|
||||
FB2E # HEBREW LETTER ALEF WITH PATAH
|
||||
FB2F # HEBREW LETTER ALEF WITH QAMATS
|
||||
FB30 # HEBREW LETTER ALEF WITH MAPIQ
|
||||
FB31 # HEBREW LETTER BET WITH DAGESH
|
||||
FB32 # HEBREW LETTER GIMEL WITH DAGESH
|
||||
FB33 # HEBREW LETTER DALET WITH DAGESH
|
||||
FB34 # HEBREW LETTER HE WITH MAPIQ
|
||||
FB35 # HEBREW LETTER VAV WITH DAGESH
|
||||
FB36 # HEBREW LETTER ZAYIN WITH DAGESH
|
||||
FB38 # HEBREW LETTER TET WITH DAGESH
|
||||
FB39 # HEBREW LETTER YOD WITH DAGESH
|
||||
FB3A # HEBREW LETTER FINAL KAF WITH DAGESH
|
||||
FB3B # HEBREW LETTER KAF WITH DAGESH
|
||||
FB3C # HEBREW LETTER LAMED WITH DAGESH
|
||||
FB3E # HEBREW LETTER MEM WITH DAGESH
|
||||
FB40 # HEBREW LETTER NUN WITH DAGESH
|
||||
FB41 # HEBREW LETTER SAMEKH WITH DAGESH
|
||||
FB43 # HEBREW LETTER FINAL PE WITH DAGESH
|
||||
FB44 # HEBREW LETTER PE WITH DAGESH
|
||||
FB46 # HEBREW LETTER TSADI WITH DAGESH
|
||||
FB47 # HEBREW LETTER QOF WITH DAGESH
|
||||
FB48 # HEBREW LETTER RESH WITH DAGESH
|
||||
FB49 # HEBREW LETTER SHIN WITH DAGESH
|
||||
FB4A # HEBREW LETTER TAV WITH DAGESH
|
||||
FB4B # HEBREW LETTER VAV WITH HOLAM
|
||||
FB4C # HEBREW LETTER BET WITH RAFE
|
||||
FB4D # HEBREW LETTER KAF WITH RAFE
|
||||
FB4E # HEBREW LETTER PE WITH RAFE
|
||||
|
||||
# Total code points: 67
|
||||
|
||||
# ================================================
|
||||
# (2) Post Composition Version precomposed characters
|
||||
#
|
||||
# These characters cannot be derived solely from the UnicodeData.txt file
|
||||
# in this version of Unicode.
|
||||
#
|
||||
# Note that characters added to the standard after the
|
||||
# Composition Version and which have canonical decomposition mappings
|
||||
# are not automatically added to this list of Post Composition
|
||||
# Version precomposed characters.
|
||||
# ================================================
|
||||
|
||||
2ADC # FORKING
|
||||
1D15E # MUSICAL SYMBOL HALF NOTE
|
||||
1D15F # MUSICAL SYMBOL QUARTER NOTE
|
||||
1D160 # MUSICAL SYMBOL EIGHTH NOTE
|
||||
1D161 # MUSICAL SYMBOL SIXTEENTH NOTE
|
||||
1D162 # MUSICAL SYMBOL THIRTY-SECOND NOTE
|
||||
1D163 # MUSICAL SYMBOL SIXTY-FOURTH NOTE
|
||||
1D164 # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
|
||||
1D1BB # MUSICAL SYMBOL MINIMA
|
||||
1D1BC # MUSICAL SYMBOL MINIMA BLACK
|
||||
1D1BD # MUSICAL SYMBOL SEMIMINIMA WHITE
|
||||
1D1BE # MUSICAL SYMBOL SEMIMINIMA BLACK
|
||||
1D1BF # MUSICAL SYMBOL FUSA WHITE
|
||||
1D1C0 # MUSICAL SYMBOL FUSA BLACK
|
||||
|
||||
# Total code points: 14
|
||||
|
||||
# ================================================
|
||||
# (3) Singleton Decompositions
|
||||
#
|
||||
# These characters can be derived from the UnicodeData.txt file
|
||||
# by including all canonically decomposable characters whose
|
||||
# canonical decomposition consists of a single character.
|
||||
#
|
||||
# These characters are simply quoted here for reference.
|
||||
# See also Full_Composition_Exclusion in DerivedNormalizationProps.txt
|
||||
# ================================================
|
||||
|
||||
# 0340..0341 [2] COMBINING GRAVE TONE MARK..COMBINING ACUTE TONE MARK
|
||||
# 0343 COMBINING GREEK KORONIS
|
||||
# 0374 GREEK NUMERAL SIGN
|
||||
# 037E GREEK QUESTION MARK
|
||||
# 0387 GREEK ANO TELEIA
|
||||
# 1F71 GREEK SMALL LETTER ALPHA WITH OXIA
|
||||
# 1F73 GREEK SMALL LETTER EPSILON WITH OXIA
|
||||
# 1F75 GREEK SMALL LETTER ETA WITH OXIA
|
||||
# 1F77 GREEK SMALL LETTER IOTA WITH OXIA
|
||||
# 1F79 GREEK SMALL LETTER OMICRON WITH OXIA
|
||||
# 1F7B GREEK SMALL LETTER UPSILON WITH OXIA
|
||||
# 1F7D GREEK SMALL LETTER OMEGA WITH OXIA
|
||||
# 1FBB GREEK CAPITAL LETTER ALPHA WITH OXIA
|
||||
# 1FBE GREEK PROSGEGRAMMENI
|
||||
# 1FC9 GREEK CAPITAL LETTER EPSILON WITH OXIA
|
||||
# 1FCB GREEK CAPITAL LETTER ETA WITH OXIA
|
||||
# 1FD3 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
|
||||
# 1FDB GREEK CAPITAL LETTER IOTA WITH OXIA
|
||||
# 1FE3 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
|
||||
# 1FEB GREEK CAPITAL LETTER UPSILON WITH OXIA
|
||||
# 1FEE..1FEF [2] GREEK DIALYTIKA AND OXIA..GREEK VARIA
|
||||
# 1FF9 GREEK CAPITAL LETTER OMICRON WITH OXIA
|
||||
# 1FFB GREEK CAPITAL LETTER OMEGA WITH OXIA
|
||||
# 1FFD GREEK OXIA
|
||||
# 2000..2001 [2] EN QUAD..EM QUAD
|
||||
# 2126 OHM SIGN
|
||||
# 212A..212B [2] KELVIN SIGN..ANGSTROM SIGN
|
||||
# 2329 LEFT-POINTING ANGLE BRACKET
|
||||
# 232A RIGHT-POINTING ANGLE BRACKET
|
||||
# F900..FA0D [270] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA0D
|
||||
# FA10 CJK COMPATIBILITY IDEOGRAPH-FA10
|
||||
# FA12 CJK COMPATIBILITY IDEOGRAPH-FA12
|
||||
# FA15..FA1E [10] CJK COMPATIBILITY IDEOGRAPH-FA15..CJK COMPATIBILITY IDEOGRAPH-FA1E
|
||||
# FA20 CJK COMPATIBILITY IDEOGRAPH-FA20
|
||||
# FA22 CJK COMPATIBILITY IDEOGRAPH-FA22
|
||||
# FA25..FA26 [2] CJK COMPATIBILITY IDEOGRAPH-FA25..CJK COMPATIBILITY IDEOGRAPH-FA26
|
||||
# FA2A..FA6D [68] CJK COMPATIBILITY IDEOGRAPH-FA2A..CJK COMPATIBILITY IDEOGRAPH-FA6D
|
||||
# FA70..FAD9 [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
|
||||
# 2F800..2FA1D [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
|
||||
|
||||
# Total code points: 1035
|
||||
|
||||
# ================================================
|
||||
# (4) Non-Starter Decompositions
|
||||
#
|
||||
# These characters can be derived from the UnicodeData.txt file
|
||||
# by including each expanding canonical decomposition
|
||||
# (i.e., those which canonically decompose to a sequence
|
||||
# of characters instead of a single character), such that:
|
||||
#
|
||||
# A. The character is not a Starter.
|
||||
#
|
||||
# OR (inclusive)
|
||||
#
|
||||
# B. The character's canonical decomposition begins
|
||||
# with a character that is not a Starter.
|
||||
#
|
||||
# Note that a "Starter" is any character with a zero combining class.
|
||||
#
|
||||
# These characters are simply quoted here for reference.
|
||||
# See also Full_Composition_Exclusion in DerivedNormalizationProps.txt
|
||||
# ================================================
|
||||
|
||||
# 0344 COMBINING GREEK DIALYTIKA TONOS
|
||||
# 0F73 TIBETAN VOWEL SIGN II
|
||||
# 0F75 TIBETAN VOWEL SIGN UU
|
||||
# 0F81 TIBETAN VOWEL SIGN REVERSED II
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# EOF
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
|
||||
0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
|
||||
0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
|
||||
0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
|
||||
08E4..0902 ; Extend # Mn [31] ARABIC CURLY FATHA..DEVANAGARI SIGN ANUSVARA
|
||||
08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
|
||||
093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE
|
||||
093C ; Extend # Mn DEVANAGARI SIGN NUKTA
|
||||
0941..0948 ; Extend # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
|
||||
@@ -216,7 +216,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
|
||||
A66F ; Extend # Mn COMBINING CYRILLIC VZMET
|
||||
A670..A672 ; Extend # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
|
||||
A674..A67D ; Extend # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
|
||||
A69F ; Extend # Mn COMBINING CYRILLIC LETTER IOTIFIED E
|
||||
A69E..A69F ; Extend # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
|
||||
A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
|
||||
A802 ; Extend # Mn SYLOTI NAGRI SIGN DVISVARA
|
||||
A806 ; Extend # Mn SYLOTI NAGRI SIGN HASANTA
|
||||
@@ -249,7 +249,7 @@ ABE8 ; Extend # Mn MEETEI MAYEK VOWEL SIGN UNAP
|
||||
ABED ; Extend # Mn MEETEI MAYEK APUN IYEK
|
||||
FB1E ; Extend # Mn HEBREW POINT JUDEO-SPANISH VARIKA
|
||||
FE00..FE0F ; Extend # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
|
||||
FE20..FE2D ; Extend # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW
|
||||
FE20..FE2F ; Extend # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
|
||||
FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
|
||||
101FD ; Extend # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
|
||||
102E0 ; Extend # Mn COPTIC EPACT THOUSANDS MARK
|
||||
@@ -271,12 +271,13 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
|
||||
11173 ; Extend # Mn MAHAJANI SIGN NUKTA
|
||||
11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
|
||||
111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
|
||||
111CA..111CC ; Extend # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
|
||||
1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
|
||||
11234 ; Extend # Mn KHOJKI SIGN ANUSVARA
|
||||
11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
|
||||
112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA
|
||||
112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
|
||||
11301 ; Extend # Mn GRANTHA SIGN CANDRABINDU
|
||||
11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
|
||||
1133C ; Extend # Mn GRANTHA SIGN NUKTA
|
||||
1133E ; Extend # Mc GRANTHA VOWEL SIGN AA
|
||||
11340 ; Extend # Mn GRANTHA VOWEL SIGN II
|
||||
@@ -293,6 +294,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
|
||||
115B2..115B5 ; Extend # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
|
||||
115BC..115BD ; Extend # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
|
||||
115BF..115C0 ; Extend # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
|
||||
115DC..115DD ; Extend # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
|
||||
11633..1163A ; Extend # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
|
||||
1163D ; Extend # Mn MODI SIGN ANUSVARA
|
||||
1163F..11640 ; Extend # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
|
||||
@@ -300,6 +302,9 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
|
||||
116AD ; Extend # Mn TAKRI VOWEL SIGN AA
|
||||
116B0..116B5 ; Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
|
||||
116B7 ; Extend # Mn TAKRI SIGN NUKTA
|
||||
1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
|
||||
11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
|
||||
11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
|
||||
16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
|
||||
16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
|
||||
16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
|
||||
@@ -311,6 +316,12 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
|
||||
1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
|
||||
1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
|
||||
1D242..1D244 ; Extend # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
|
||||
1DA00..1DA36 ; Extend # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
|
||||
1DA3B..1DA6C ; Extend # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
|
||||
1DA75 ; Extend # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
|
||||
1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK
|
||||
1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
|
||||
1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
|
||||
1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
|
||||
E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
|
||||
1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
|
||||
@@ -368,8 +379,6 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
|
||||
1929..192B ; SpacingMark # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
|
||||
1930..1931 ; SpacingMark # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
|
||||
1933..1938 ; SpacingMark # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
|
||||
19B5..19B7 ; SpacingMark # Mc [3] NEW TAI LUE VOWEL SIGN E..NEW TAI LUE VOWEL SIGN O
|
||||
19BA ; SpacingMark # Mc NEW TAI LUE VOWEL SIGN AY
|
||||
1A19..1A1A ; SpacingMark # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
|
||||
1A55 ; SpacingMark # Mc TAI THAM CONSONANT SIGN MEDIAL RA
|
||||
1A57 ; SpacingMark # Mc TAI THAM CONSONANT SIGN LA TANG LAI
|
||||
@@ -443,6 +452,8 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK
|
||||
116AC ; SpacingMark # Mc TAKRI SIGN VISARGA
|
||||
116AE..116AF ; SpacingMark # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
|
||||
116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA
|
||||
11720..11721 ; SpacingMark # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
|
||||
11726 ; SpacingMark # Mc AHOM VOWEL SIGN E
|
||||
16F51..16F7E ; SpacingMark # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
|
||||
1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
|
||||
1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
|
||||
|
||||
+2054
-107
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
0009..000D ; White_Space # Cc [5] <control-0009>..<control-000D>
|
||||
0020 ; White_Space # Zs SPACE
|
||||
0085 ; White_Space # Cc <control-0085>
|
||||
00A0 ; White_Space # Zs NO-BREAK SPACE
|
||||
1680 ; White_Space # Zs OGHAM SPACE MARK
|
||||
2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE
|
||||
2028 ; White_Space # Zl LINE SEPARATOR
|
||||
2029 ; White_Space # Zp PARAGRAPH SEPARATOR
|
||||
202F ; White_Space # Zs NARROW NO-BREAK SPACE
|
||||
205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
|
||||
3000 ; White_Space # Zs IDEOGRAPHIC SPACE
|
||||
+327
-274
@@ -1,231 +1,25 @@
|
||||
to_binary = fn
|
||||
"" ->
|
||||
nil
|
||||
codepoints ->
|
||||
codepoints = :binary.split(codepoints, " ", [:global])
|
||||
Enum.reduce codepoints, "", fn(codepoint, acc) ->
|
||||
acc <> <<String.to_integer(codepoint, 16)::utf8>>
|
||||
end
|
||||
end
|
||||
|
||||
defmodule String.Unicode do
|
||||
@moduledoc false
|
||||
def version, do: {7, 0, 0}
|
||||
|
||||
data_path = Path.join(__DIR__, "UnicodeData.txt")
|
||||
|
||||
{codes, whitespace} = Enum.reduce File.stream!(data_path), {[], []}, fn(line, {cacc, wacc}) ->
|
||||
[codepoint, _name, _category,
|
||||
_class, bidi, _decomposition,
|
||||
_numeric_1, _numeric_2, _numeric_3,
|
||||
_bidi_mirror, _unicode_1, _iso,
|
||||
upper, lower, title] = :binary.split(line, ";", [:global])
|
||||
|
||||
title = :binary.part(title, 0, byte_size(title) - 1)
|
||||
|
||||
cond do
|
||||
upper != "" or lower != "" or title != "" ->
|
||||
{[{to_binary.(codepoint),
|
||||
to_binary.(upper),
|
||||
to_binary.(lower),
|
||||
to_binary.(title)} | cacc],
|
||||
wacc}
|
||||
bidi in ["B", "S", "WS"] ->
|
||||
{cacc, [to_binary.(codepoint) | wacc]}
|
||||
true ->
|
||||
{cacc, wacc}
|
||||
end
|
||||
end
|
||||
|
||||
special_path = Path.join(__DIR__, "SpecialCasing.txt")
|
||||
|
||||
codes = Enum.reduce File.stream!(special_path), codes, fn(line, acc) ->
|
||||
[codepoint, lower, title, upper, _] = :binary.split(line, "; ", [:global])
|
||||
key = to_binary.(codepoint)
|
||||
:lists.keystore(key, 1, acc, {key,
|
||||
to_binary.(upper),
|
||||
to_binary.(lower),
|
||||
to_binary.(title)})
|
||||
end
|
||||
|
||||
# Downcase
|
||||
|
||||
def downcase(string), do: downcase(string, "")
|
||||
|
||||
for {codepoint, _upper, lower, _title} <- codes, lower && lower != codepoint do
|
||||
defp downcase(unquote(codepoint) <> rest, acc) do
|
||||
downcase(rest, acc <> unquote(lower))
|
||||
end
|
||||
end
|
||||
|
||||
defp downcase(<<char, rest::binary>>, acc) do
|
||||
downcase(rest, <<acc::binary, char>>)
|
||||
end
|
||||
|
||||
defp downcase("", acc), do: acc
|
||||
|
||||
# Upcase
|
||||
|
||||
def upcase(string), do: upcase(string, "")
|
||||
|
||||
for {codepoint, upper, _lower, _title} <- codes, upper && upper != codepoint do
|
||||
defp upcase(unquote(codepoint) <> rest, acc) do
|
||||
upcase(rest, acc <> unquote(upper))
|
||||
end
|
||||
end
|
||||
|
||||
defp upcase(<<char, rest::binary>>, acc) do
|
||||
upcase(rest, <<acc::binary, char>>)
|
||||
end
|
||||
|
||||
defp upcase("", acc), do: acc
|
||||
|
||||
# Titlecase once
|
||||
|
||||
def titlecase_once(""), do: {"", ""}
|
||||
|
||||
for {codepoint, _upper, _lower, title} <- codes, title && title != codepoint do
|
||||
def titlecase_once(unquote(codepoint) <> rest) do
|
||||
{unquote(title), rest}
|
||||
end
|
||||
end
|
||||
|
||||
def titlecase_once(<<char, rest::binary>>) do
|
||||
{<<char>>, rest}
|
||||
end
|
||||
|
||||
# Strip
|
||||
|
||||
def lstrip(string)
|
||||
|
||||
def lstrip(""), do: ""
|
||||
|
||||
for codepoint <- whitespace do
|
||||
def lstrip(unquote(codepoint) <> rest) do
|
||||
lstrip(rest)
|
||||
end
|
||||
end
|
||||
|
||||
def lstrip(string) when is_binary(string), do: string
|
||||
|
||||
@whitespace_max_size 3
|
||||
for codepoint <- whitespace do
|
||||
# We need to increment @whitespace_max_size as well
|
||||
# as the small table (_s) if we add a new entry here.
|
||||
case byte_size(codepoint) do
|
||||
3 ->
|
||||
defp do_rstrip_l(unquote(codepoint)), do: -3
|
||||
2 ->
|
||||
defp do_rstrip_l(<<_, unquote(codepoint)>>), do: -2
|
||||
|
||||
defp do_rstrip_s(unquote(codepoint)), do: <<>>
|
||||
1 ->
|
||||
defp do_rstrip_l(<<unquote(codepoint), unquote(codepoint), unquote(codepoint)>>), do: -3
|
||||
defp do_rstrip_l(<<_, unquote(codepoint), unquote(codepoint)>>), do: -2
|
||||
defp do_rstrip_l(<<_, _, unquote(codepoint)>>), do: -1
|
||||
|
||||
defp do_rstrip_s(<<x, unquote(codepoint)>>), do: do_rstrip_s(<<x>>)
|
||||
defp do_rstrip_s(unquote(codepoint)), do: <<>>
|
||||
end
|
||||
end
|
||||
|
||||
defp do_rstrip_l(_), do: 0
|
||||
defp do_rstrip_s(o), do: o
|
||||
|
||||
def rstrip(string) when is_binary(string) do
|
||||
rstrip(string, byte_size(string))
|
||||
end
|
||||
|
||||
defp rstrip(string, size) when size < @whitespace_max_size do
|
||||
do_rstrip_s(string)
|
||||
end
|
||||
|
||||
defp rstrip(string, size) do
|
||||
trail = binary_part(string, size, -@whitespace_max_size)
|
||||
case do_rstrip_l(trail) do
|
||||
0 -> string
|
||||
x -> rstrip(binary_part(string, 0, size + x), size + x)
|
||||
end
|
||||
end
|
||||
|
||||
# Split
|
||||
|
||||
def split(""), do: []
|
||||
|
||||
def split(string) when is_binary(string) do
|
||||
:lists.reverse do_split(string, "", [])
|
||||
end
|
||||
|
||||
for codepoint <- whitespace do
|
||||
defp do_split(unquote(codepoint) <> rest, buffer, acc) do
|
||||
do_split(rest, "", add_buffer_to_acc(buffer, acc))
|
||||
end
|
||||
end
|
||||
|
||||
defp do_split(<<char, rest::binary>>, buffer, acc) do
|
||||
do_split(rest, <<buffer::binary, char>>, acc)
|
||||
end
|
||||
|
||||
defp do_split(<<>>, buffer, acc) do
|
||||
add_buffer_to_acc(buffer, acc)
|
||||
end
|
||||
|
||||
@compile {:inline, add_buffer_to_acc: 2}
|
||||
|
||||
defp add_buffer_to_acc("", acc), do: acc
|
||||
defp add_buffer_to_acc(buffer, acc), do: [buffer|acc]
|
||||
|
||||
# Codepoints
|
||||
|
||||
def next_codepoint(<<cp::utf8, rest::binary>>) do
|
||||
{<<cp::utf8>>, rest}
|
||||
end
|
||||
|
||||
def next_codepoint(<<cp, rest::binary>>) do
|
||||
{<<cp>>, rest}
|
||||
end
|
||||
|
||||
def next_codepoint(<<>>) do
|
||||
nil
|
||||
end
|
||||
|
||||
def codepoints(binary) when is_binary(binary) do
|
||||
do_codepoints(next_codepoint(binary))
|
||||
end
|
||||
|
||||
defp do_codepoints({c, rest}) do
|
||||
[c|do_codepoints(next_codepoint(rest))]
|
||||
end
|
||||
|
||||
defp do_codepoints(nil) do
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defmodule String.Graphemes do
|
||||
@moduledoc false
|
||||
def version, do: {8, 0, 0}
|
||||
|
||||
cluster_path = Path.join(__DIR__, "GraphemeBreakProperty.txt")
|
||||
regex = ~r/(?:^([0-9A-F]+)(?:\.\.([0-9A-F]+))?)\s+;\s(\w+)/m
|
||||
|
||||
to_range = fn
|
||||
first, "" ->
|
||||
[<<String.to_integer(first, 16)::utf8>>]
|
||||
first, last ->
|
||||
range = String.to_integer(first, 16)..String.to_integer(last, 16)
|
||||
Enum.map(range, fn(int) -> <<int::utf8>> end)
|
||||
end
|
||||
|
||||
cluster = Enum.reduce File.stream!(cluster_path), %{}, fn(line, dict) ->
|
||||
cluster = Enum.reduce File.stream!(cluster_path), %{}, fn line, dict ->
|
||||
[_full, first, last, class] = Regex.run(regex, line)
|
||||
|
||||
# Skip surrogates
|
||||
if first == "D800" and last == "DFFF" do
|
||||
dict
|
||||
else
|
||||
list = to_range.(first, last)
|
||||
Map.update(dict, class, list, &(&1 ++ list))
|
||||
end
|
||||
codepoints =
|
||||
case {first, last} do
|
||||
{"D800", "DFFF"} ->
|
||||
[]
|
||||
{first, ""} ->
|
||||
[<<String.to_integer(first, 16)::utf8>>]
|
||||
{first, last} ->
|
||||
range = String.to_integer(first, 16)..String.to_integer(last, 16)
|
||||
Enum.map(range, fn int -> <<int::utf8>> end)
|
||||
end
|
||||
|
||||
Map.update(dict, class, codepoints, &(&1 ++ codepoints))
|
||||
end
|
||||
|
||||
# There is no codepoint marked as Prepend by Unicode 6.3.0
|
||||
@@ -371,7 +165,7 @@ defmodule String.Graphemes do
|
||||
# {size, rest}
|
||||
# end
|
||||
|
||||
## Tight-loop implementations
|
||||
# Graphemes
|
||||
|
||||
def graphemes(binary) when is_binary(binary) do
|
||||
do_graphemes(next_grapheme_size(binary), binary)
|
||||
@@ -385,6 +179,8 @@ defmodule String.Graphemes do
|
||||
[]
|
||||
end
|
||||
|
||||
# Length
|
||||
|
||||
def length(string) do
|
||||
do_length(next_grapheme_size(string), 0)
|
||||
end
|
||||
@@ -395,6 +191,8 @@ defmodule String.Graphemes do
|
||||
|
||||
defp do_length(nil, acc), do: acc
|
||||
|
||||
# Split at
|
||||
|
||||
def split_at(string, pos) do
|
||||
do_split_at(string, 0, pos, 0)
|
||||
end
|
||||
@@ -409,34 +207,272 @@ defmodule String.Graphemes do
|
||||
defp do_split_at(string, acc, desired_pos, desired_pos) do
|
||||
{acc, string}
|
||||
end
|
||||
|
||||
# Codepoints
|
||||
|
||||
def next_codepoint(<<cp::utf8, rest::binary>>) do
|
||||
{<<cp::utf8>>, rest}
|
||||
end
|
||||
|
||||
def next_codepoint(<<cp, rest::binary>>) do
|
||||
{<<cp>>, rest}
|
||||
end
|
||||
|
||||
def next_codepoint(<<>>) do
|
||||
nil
|
||||
end
|
||||
|
||||
def codepoints(binary) when is_binary(binary) do
|
||||
do_codepoints(next_codepoint(binary))
|
||||
end
|
||||
|
||||
defp do_codepoints({c, rest}) do
|
||||
[c|do_codepoints(next_codepoint(rest))]
|
||||
end
|
||||
|
||||
defp do_codepoints(nil) do
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
to_binary = fn
|
||||
"" ->
|
||||
nil
|
||||
codepoints ->
|
||||
codepoints
|
||||
|> :binary.split(" ", [:global])
|
||||
|> Enum.map(&<<String.to_integer(&1, 16)::utf8>>)
|
||||
|> IO.iodata_to_binary
|
||||
end
|
||||
|
||||
data_path = Path.join(__DIR__, "UnicodeData.txt")
|
||||
|
||||
{codes, non_breakable, decompositions, combining_classes} =
|
||||
Enum.reduce File.stream!(data_path), {[], [], %{}, %{}}, fn line, {cacc, wacc, dacc, kacc} ->
|
||||
[codepoint, _name, _category,
|
||||
class, _bidi, decomposition,
|
||||
_numeric_1, _numeric_2, _numeric_3,
|
||||
_bidi_mirror, _unicode_1, _iso,
|
||||
upper, lower, title] = :binary.split(line, ";", [:global])
|
||||
|
||||
title = :binary.part(title, 0, byte_size(title) - 1)
|
||||
|
||||
cacc =
|
||||
if upper != "" or lower != "" or title != "" do
|
||||
[{to_binary.(codepoint), to_binary.(upper), to_binary.(lower), to_binary.(title)} | cacc]
|
||||
else
|
||||
cacc
|
||||
end
|
||||
|
||||
wacc =
|
||||
case decomposition do
|
||||
"<noBreak>" <> _ -> [to_binary.(codepoint)|wacc]
|
||||
_ -> wacc
|
||||
end
|
||||
|
||||
dacc =
|
||||
case decomposition do
|
||||
<<h, _::binary>> when h != ?< -> # Decomposition
|
||||
decomposition =
|
||||
decomposition
|
||||
|> :binary.split(" ", [:global])
|
||||
|> Enum.map(&String.to_integer(&1, 16))
|
||||
Map.put(dacc, String.to_integer(codepoint, 16), decomposition)
|
||||
_ ->
|
||||
dacc
|
||||
end
|
||||
|
||||
kacc =
|
||||
case Integer.parse(class) do
|
||||
{0, ""} -> kacc
|
||||
{n, ""} -> Map.put(kacc, String.to_integer(codepoint, 16), n)
|
||||
end
|
||||
|
||||
{cacc, wacc, dacc, kacc}
|
||||
end
|
||||
|
||||
defmodule String.Casing do
|
||||
@moduledoc false
|
||||
|
||||
special_path = Path.join(__DIR__, "SpecialCasing.txt")
|
||||
|
||||
codes = Enum.reduce File.stream!(special_path), codes, fn line, acc ->
|
||||
[codepoint, lower, title, upper, _] = :binary.split(line, "; ", [:global])
|
||||
key = to_binary.(codepoint)
|
||||
:lists.keystore(key, 1, acc, {key,
|
||||
to_binary.(upper),
|
||||
to_binary.(lower),
|
||||
to_binary.(title)})
|
||||
end
|
||||
|
||||
# Downcase
|
||||
|
||||
def downcase(string), do: downcase(string, "")
|
||||
|
||||
for {codepoint, _upper, lower, _title} <- codes, lower && lower != codepoint do
|
||||
defp downcase(unquote(codepoint) <> rest, acc) do
|
||||
downcase(rest, acc <> unquote(lower))
|
||||
end
|
||||
end
|
||||
|
||||
defp downcase(<<char, rest::binary>>, acc) do
|
||||
downcase(rest, <<acc::binary, char>>)
|
||||
end
|
||||
|
||||
defp downcase("", acc), do: acc
|
||||
|
||||
# Upcase
|
||||
|
||||
def upcase(string), do: upcase(string, "")
|
||||
|
||||
for {codepoint, upper, _lower, _title} <- codes, upper && upper != codepoint do
|
||||
defp upcase(unquote(codepoint) <> rest, acc) do
|
||||
upcase(rest, acc <> unquote(upper))
|
||||
end
|
||||
end
|
||||
|
||||
defp upcase(<<char, rest::binary>>, acc) do
|
||||
upcase(rest, <<acc::binary, char>>)
|
||||
end
|
||||
|
||||
defp upcase("", acc), do: acc
|
||||
|
||||
# Titlecase once
|
||||
|
||||
def titlecase_once(""), do: {"", ""}
|
||||
|
||||
for {codepoint, _upper, _lower, title} <- codes, title && title != codepoint do
|
||||
def titlecase_once(unquote(codepoint) <> rest) do
|
||||
{unquote(title), rest}
|
||||
end
|
||||
end
|
||||
|
||||
def titlecase_once(<<char, rest::binary>>) do
|
||||
{<<char>>, rest}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule String.Break do
|
||||
@moduledoc false
|
||||
@whitespace_max_size 3
|
||||
|
||||
# WhiteSpace.txt is extracted from Unicode's PropList.txt (just the White_Space property)
|
||||
prop_path = Path.join(__DIR__, "WhiteSpace.txt")
|
||||
|
||||
whitespace = Enum.reduce File.stream!(prop_path), [], fn line, acc ->
|
||||
case line |> :binary.split(";") |> hd do
|
||||
<<first::4-bytes, "..", last::4-bytes, _::binary>> ->
|
||||
first = String.to_integer(first, 16)
|
||||
last = String.to_integer(last, 16)
|
||||
Enum.map(first..last, fn int -> <<int::utf8>> end) ++ acc
|
||||
<<single::4-bytes, _::binary>> ->
|
||||
[<<String.to_integer(single, 16)::utf8>> | acc]
|
||||
end
|
||||
end
|
||||
|
||||
# lstrip
|
||||
|
||||
def lstrip(""), do: ""
|
||||
|
||||
for codepoint <- whitespace do
|
||||
def lstrip(unquote(codepoint) <> rest) do
|
||||
lstrip(rest)
|
||||
end
|
||||
end
|
||||
|
||||
def lstrip(string) when is_binary(string), do: string
|
||||
|
||||
# rstrip
|
||||
|
||||
for codepoint <- whitespace do
|
||||
# We need to increment @whitespace_max_size as well
|
||||
# as the small table (_s) if we add a new entry here.
|
||||
case byte_size(codepoint) do
|
||||
3 ->
|
||||
defp do_rstrip_l(unquote(codepoint)), do: -3
|
||||
2 ->
|
||||
defp do_rstrip_l(<<_, unquote(codepoint)>>), do: -2
|
||||
|
||||
defp do_rstrip_s(unquote(codepoint)), do: <<>>
|
||||
1 ->
|
||||
defp do_rstrip_l(<<unquote(codepoint), unquote(codepoint), unquote(codepoint)>>), do: -3
|
||||
defp do_rstrip_l(<<_, unquote(codepoint), unquote(codepoint)>>), do: -2
|
||||
defp do_rstrip_l(<<_, _, unquote(codepoint)>>), do: -1
|
||||
|
||||
defp do_rstrip_s(<<x, unquote(codepoint)>>), do: do_rstrip_s(<<x>>)
|
||||
defp do_rstrip_s(unquote(codepoint)), do: <<>>
|
||||
end
|
||||
end
|
||||
|
||||
defp do_rstrip_l(_), do: 0
|
||||
defp do_rstrip_s(o), do: o
|
||||
|
||||
def rstrip(string) when is_binary(string) do
|
||||
rstrip(string, byte_size(string))
|
||||
end
|
||||
|
||||
defp rstrip(string, size) when size < @whitespace_max_size do
|
||||
do_rstrip_s(string)
|
||||
end
|
||||
|
||||
defp rstrip(string, size) do
|
||||
trail = binary_part(string, size, -@whitespace_max_size)
|
||||
case do_rstrip_l(trail) do
|
||||
0 -> string
|
||||
x -> rstrip(binary_part(string, 0, size + x), size + x)
|
||||
end
|
||||
end
|
||||
|
||||
# Split
|
||||
|
||||
def split(""), do: []
|
||||
|
||||
def split(string) when is_binary(string) do
|
||||
:lists.reverse do_split(string, "", [])
|
||||
end
|
||||
|
||||
for codepoint <- whitespace -- non_breakable do
|
||||
defp do_split(unquote(codepoint) <> rest, buffer, acc) do
|
||||
do_split(rest, "", add_buffer_to_acc(buffer, acc))
|
||||
end
|
||||
end
|
||||
|
||||
defp do_split(<<char, rest::binary>>, buffer, acc) do
|
||||
do_split(rest, <<buffer::binary, char>>, acc)
|
||||
end
|
||||
|
||||
defp do_split(<<>>, buffer, acc) do
|
||||
add_buffer_to_acc(buffer, acc)
|
||||
end
|
||||
|
||||
@compile {:inline, add_buffer_to_acc: 2}
|
||||
|
||||
defp add_buffer_to_acc("", acc), do: acc
|
||||
defp add_buffer_to_acc(buffer, acc), do: [buffer|acc]
|
||||
|
||||
# Decompose
|
||||
|
||||
def decompose(entries, map) do
|
||||
for entry <- entries do
|
||||
case map do
|
||||
%{^entry => match} -> decompose(match, map)
|
||||
%{} -> <<entry::utf8>>
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule String.Normalizer do
|
||||
@moduledoc false
|
||||
|
||||
decomposition_path = Path.join(__DIR__, "Decomposition.txt")
|
||||
exclusions_path = Path.join(__DIR__, "CompositionExclusions.txt")
|
||||
|
||||
decompositions = Enum.reduce File.stream!(decomposition_path), [], fn(line, acc) ->
|
||||
[key, first, second, third, fourth, _] = :binary.split(line, ";", [:global])
|
||||
decomposition = to_binary.(first) <> (to_binary.(second) || "") <>
|
||||
(to_binary.(third) || "") <>
|
||||
(to_binary.(fourth) || "")
|
||||
[{to_binary.(key), decomposition} | acc]
|
||||
end
|
||||
|
||||
composition_path = Path.join(__DIR__, "Composition.txt")
|
||||
|
||||
compositions = Enum.reduce File.stream!(composition_path), [], fn(line, acc) ->
|
||||
[first, second, composition, _] = :binary.split(line, ";", [:global])
|
||||
key = to_binary.(first) <> to_binary.(second)
|
||||
[{key, to_binary.(composition)} | acc]
|
||||
end
|
||||
|
||||
combining_class_path = Path.join(__DIR__, "CombiningClasses.txt")
|
||||
|
||||
combining_classes = Enum.reduce File.stream!(combining_class_path), [], fn(line, acc) ->
|
||||
[codepoint, class, _] = :binary.split(line, ";", [:global])
|
||||
[{String.to_integer(codepoint, 16), class} | acc]
|
||||
compositions = Enum.reduce File.stream!(exclusions_path), decompositions, fn
|
||||
<<h, _::binary>> = line, acc when h in ?0..?9 or h in ?A..?F ->
|
||||
[codepoint, _] = :binary.split(line, " ")
|
||||
Map.delete(acc, String.to_integer(codepoint, 16))
|
||||
_, acc ->
|
||||
acc
|
||||
end
|
||||
|
||||
# Normalize
|
||||
@@ -465,18 +501,12 @@ defmodule String.Normalizer do
|
||||
normalize_nfd(rest, acc <> binary)
|
||||
end
|
||||
|
||||
for {binary, decomposition} <- decompositions do
|
||||
defp normalize_nfd(unquote(binary) <> rest, acc) do
|
||||
normalize_nfd(rest, acc <> unquote(decomposition))
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_nfd(binary, acc) do
|
||||
{n, rest} = String.Graphemes.next_grapheme_size(binary)
|
||||
{n, rest} = String.Unicode.next_grapheme_size(binary)
|
||||
part = :binary.part(binary, 0, n)
|
||||
case n do
|
||||
1 -> normalize_nfd(rest, acc <> part)
|
||||
_ -> normalize_nfd(rest, acc <> canonical_order(part))
|
||||
1 -> normalize_nfc(rest, acc <> part)
|
||||
_ -> normalize_nfd(rest, acc <> canonical_order(part, []))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -487,7 +517,7 @@ defmodule String.Normalizer do
|
||||
end
|
||||
|
||||
defp normalize_nfc(binary, acc) do
|
||||
{n, rest} = String.Graphemes.next_grapheme_size(binary)
|
||||
{n, rest} = String.Unicode.next_grapheme_size(binary)
|
||||
part = :binary.part(binary, 0, n)
|
||||
case n do
|
||||
1 -> normalize_nfc(rest, acc <> part)
|
||||
@@ -495,11 +525,33 @@ defmodule String.Normalizer do
|
||||
end
|
||||
end
|
||||
|
||||
defp canonical_order(binary) do
|
||||
binary
|
||||
|> :unicode.characters_to_list()
|
||||
|> Enum.sort_by(&combining_class/1)
|
||||
|> :unicode.characters_to_binary()
|
||||
for {cp, decomposition} <- decompositions do
|
||||
decomposition =
|
||||
decomposition
|
||||
|> String.Break.decompose(decompositions)
|
||||
|> IO.iodata_to_binary()
|
||||
|
||||
defp canonical_order(unquote(<<cp::utf8>>) <> rest, acc) do
|
||||
canonical_order(unquote(decomposition) <> rest, acc)
|
||||
end
|
||||
end
|
||||
defp canonical_order(<<h::utf8, t::binary>>, acc) do
|
||||
case combining_class(h) do
|
||||
0 -> canonical_order(acc) <> canonical_order(t, [{h, 0}])
|
||||
n -> canonical_order(t, [{h, n}|acc])
|
||||
end
|
||||
end
|
||||
defp canonical_order(<<>>, acc) do
|
||||
canonical_order(acc)
|
||||
end
|
||||
|
||||
defp canonical_order([{x, _}]) do
|
||||
<<x::utf8>>
|
||||
end
|
||||
defp canonical_order(acc) do
|
||||
:lists.keysort(2, Enum.reverse(acc))
|
||||
|> Enum.map(&<<elem(&1, 0)::utf8>>)
|
||||
|> IO.iodata_to_binary
|
||||
end
|
||||
|
||||
for {codepoint, class} <- combining_classes do
|
||||
@@ -508,8 +560,6 @@ defmodule String.Normalizer do
|
||||
|
||||
defp combining_class(_), do: 0
|
||||
|
||||
defp compose(<<_::utf8>> = binary), do: binary
|
||||
|
||||
defp compose(<<lead::utf8, vowel::utf8, rest::binary>>) when lead in 0x1100..0x1112 and vowel in 0x1161..0x1175 do
|
||||
codepoint = 0xAC00 + ((lead - 0x1100) * 588) + ((vowel - 0x1161) * 28)
|
||||
case rest do
|
||||
@@ -520,29 +570,32 @@ defmodule String.Normalizer do
|
||||
end
|
||||
end
|
||||
|
||||
for {binary, composition} <- compositions do
|
||||
defp compose(unquote(binary)), do: unquote(composition)
|
||||
defp compose(binary) do
|
||||
compose_one(binary) || (
|
||||
<<cp::utf8, rest::binary>> = binary
|
||||
compose_many(rest, <<cp::utf8>>, "", combining_class(cp) - 1)
|
||||
)
|
||||
end
|
||||
|
||||
defp compose(<<cp::utf8, rest::binary>>) do
|
||||
compose(rest, <<cp::utf8>>, "", combining_class(cp) - 1)
|
||||
end
|
||||
defp compose_many("", base, accents, _), do: base <> accents
|
||||
|
||||
defp compose("", base, accents, _), do: base <> accents
|
||||
|
||||
defp compose(<<cp::utf8, rest::binary>>, base, accents, last_class) do
|
||||
defp compose_many(<<cp::utf8, rest::binary>>, base, accents, last_class) do
|
||||
part_class = combining_class(cp)
|
||||
combined = <<base::binary, cp::utf8>>
|
||||
if last_class < part_class and composable?(combined) do
|
||||
compose(rest, compose(combined), accents, last_class)
|
||||
if composed = (last_class < part_class && compose_one(combined)) do
|
||||
compose_many(rest, composed, accents, last_class)
|
||||
else
|
||||
compose(rest, base, <<accents::binary, cp::utf8>>, part_class)
|
||||
compose_many(rest, base, <<accents::binary, cp::utf8>>, part_class)
|
||||
end
|
||||
end
|
||||
|
||||
for {binary, _} <- compositions do
|
||||
defp composable?(unquote(binary)), do: true
|
||||
# Compositions:
|
||||
# 1. We must exclude compositions with a single codepoint
|
||||
# 2. We must exclude compositions that do not start with 0 combining class
|
||||
for {cp, [fst, snd]} <- compositions,
|
||||
Map.get(combining_classes, fst, 0) == 0 do
|
||||
defp compose_one(unquote(<<fst::utf8, snd::utf8>>)), do: unquote(<<cp::utf8>>)
|
||||
end
|
||||
|
||||
defp composable?(_), do: false
|
||||
defp compose_one(_), do: nil
|
||||
end
|
||||
|
||||
@@ -58,7 +58,7 @@ defmodule ExUnit do
|
||||
|
||||
@typedoc "The error state returned by ExUnit.Test and ExUnit.TestCase"
|
||||
@type state :: nil | {:failed, failed} | {:skip, binary} | {:invalid, module}
|
||||
@type failed :: {Exception.kind, reason :: term, stacktrace :: [tuple]}
|
||||
@type failed :: [{Exception.kind, reason :: term, stacktrace :: [tuple]}]
|
||||
|
||||
defmodule Test do
|
||||
@moduledoc """
|
||||
|
||||
@@ -102,15 +102,16 @@ defmodule ExUnit.Assertions do
|
||||
# is not nil nor false. We need to rewrite the if
|
||||
# to avoid silly warnings though.
|
||||
return =
|
||||
no_warning(quote do
|
||||
if right do
|
||||
right
|
||||
else
|
||||
no_warning(quote do
|
||||
case right do
|
||||
x when x in [nil, false] ->
|
||||
raise ExUnit.AssertionError,
|
||||
expr: expr,
|
||||
message: "Expected truthy, got #{inspect right}"
|
||||
end
|
||||
end)
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end)
|
||||
|
||||
quote do
|
||||
right = unquote(right)
|
||||
@@ -401,24 +402,26 @@ defmodule ExUnit.Assertions do
|
||||
end
|
||||
|
||||
defp collect_vars_from_pattern(expr) do
|
||||
{_, vars} =
|
||||
Macro.prewalk(expr, [], fn
|
||||
{:::, _, [left, _]}, acc ->
|
||||
{[left], acc}
|
||||
{skip, _, [_]}, acc when skip in [:^, :@] ->
|
||||
{:ok, acc}
|
||||
{:_, _, context}, acc when is_atom(context) ->
|
||||
{:ok, acc}
|
||||
{name, _, context}, acc when is_atom(name) and is_atom(context) ->
|
||||
{:ok, [{name, [generated: true], context}|acc]}
|
||||
node, acc ->
|
||||
{node, acc}
|
||||
end)
|
||||
Enum.uniq(vars)
|
||||
Macro.prewalk(expr, [], fn
|
||||
{:::, _, [left, _]}, acc ->
|
||||
{[left], acc}
|
||||
{skip, _, [_]}, acc when skip in [:^, :@] ->
|
||||
{:ok, acc}
|
||||
{:_, _, context}, acc when is_atom(context) ->
|
||||
{:ok, acc}
|
||||
{name, meta, context}, acc when is_atom(name) and is_atom(context) ->
|
||||
{:ok, [{name, [generated: true] ++ meta, context} | acc]}
|
||||
node, acc ->
|
||||
{node, acc}
|
||||
end)
|
||||
|> elem(1)
|
||||
end
|
||||
|
||||
defp no_warning({name, meta, args}) do
|
||||
{name, [line: -1] ++ meta, args}
|
||||
defp no_warning({name, meta, [expr, [do: clauses]]}) do
|
||||
clauses = Enum.map clauses, fn {:->, meta, args} ->
|
||||
{:->, [generated: true] ++ Keyword.put(meta, :line, -1), args}
|
||||
end
|
||||
{name, meta, [expr, [do: clauses]]}
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
@@ -146,6 +146,8 @@ defmodule ExUnit.Callbacks do
|
||||
|
||||
## Helpers
|
||||
|
||||
@reserved ~w(case test line file)a
|
||||
|
||||
@doc false
|
||||
def __merge__(_mod, context, :ok) do
|
||||
{:ok, context}
|
||||
@@ -163,12 +165,16 @@ defmodule ExUnit.Callbacks do
|
||||
raise_merge_failed!(mod, data)
|
||||
end
|
||||
|
||||
defp context_merge(_mod, context, %{} = data) do
|
||||
Map.merge(context, data)
|
||||
defp context_merge(mod, context, %{} = data) do
|
||||
Map.merge(context, data, fn
|
||||
_, v, v -> v
|
||||
k, _, v when k in @reserved -> raise_merge_reserved!(mod, k, v)
|
||||
_, _, v -> v
|
||||
end)
|
||||
end
|
||||
|
||||
defp context_merge(_mod, context, data) when is_list(data) do
|
||||
Enum.into(data, context)
|
||||
defp context_merge(mod, context, data) when is_list(data) do
|
||||
context_merge(mod, context, Map.new(data))
|
||||
end
|
||||
|
||||
defp context_merge(mod, _context, data) do
|
||||
@@ -177,7 +183,12 @@ defmodule ExUnit.Callbacks do
|
||||
|
||||
defp raise_merge_failed!(mod, data) do
|
||||
raise "expected ExUnit callback in #{inspect mod} to return :ok " <>
|
||||
" or {:ok, keyword | map}, got #{inspect data} instead"
|
||||
"or {:ok, keyword | map}, got #{inspect data} instead"
|
||||
end
|
||||
|
||||
defp raise_merge_reserved!(mod, key, value) do
|
||||
raise "expected ExUnit callback in #{inspect mod} is trying to set " <>
|
||||
"reserved field #{inspect key} to #{inspect value}"
|
||||
end
|
||||
|
||||
defp escape(contents) do
|
||||
|
||||
@@ -114,10 +114,11 @@ defmodule ExUnit.Case do
|
||||
The following tags are set automatically by ExUnit and are
|
||||
therefore reserved:
|
||||
|
||||
* `:case` - the test case module
|
||||
* `:test` - the test name
|
||||
* `:line` - the line on which the test was defined
|
||||
* `:file` - the file on which the test was defined
|
||||
* `:case` - the test case module
|
||||
* `:test` - the test name
|
||||
* `:line` - the line on which the test was defined
|
||||
* `:file` - the file on which the test was defined
|
||||
* `:async` - if the test case is in async mode
|
||||
|
||||
The following tags customize how tests behaves:
|
||||
|
||||
@@ -174,7 +175,7 @@ defmodule ExUnit.Case do
|
||||
|
||||
This default can be overriden by `@tag capture_log: false` or `@moduletag capture_log: false`.
|
||||
|
||||
Since `setup_all` blocks don't belong to a specific test, log messages generated in them (or
|
||||
Since `setup_all` blocks don't belong to a specific test, log messages generated in them (or
|
||||
between tests) are never captured. If you want to suppress these messages as well, remove the
|
||||
console backend globally:
|
||||
|
||||
@@ -193,20 +194,16 @@ defmodule ExUnit.Case do
|
||||
end
|
||||
|
||||
quote do
|
||||
async = !!unquote(async)
|
||||
|
||||
unless Module.get_attribute(__MODULE__, :ex_unit_tests) do
|
||||
Enum.each [:ex_unit_tests, :tag, :moduletag],
|
||||
&Module.register_attribute(__MODULE__, &1, accumulate: true)
|
||||
|
||||
if unquote(async) do
|
||||
@moduletag async: true
|
||||
ExUnit.Server.add_async_case(__MODULE__)
|
||||
else
|
||||
@moduletag async: false
|
||||
ExUnit.Server.add_sync_case(__MODULE__)
|
||||
end
|
||||
|
||||
@moduletag async: async
|
||||
@before_compile ExUnit.Case
|
||||
@ex_unit_test_names %{}
|
||||
@ex_unit_async async
|
||||
use ExUnit.Callbacks
|
||||
end
|
||||
|
||||
@@ -254,7 +251,7 @@ defmodule ExUnit.Case do
|
||||
|
||||
quote bind_quoted: binding do
|
||||
test = :"test #{message}"
|
||||
ExUnit.Case.__on_definition__(__ENV__, test)
|
||||
ExUnit.Case.__on_definition__(__ENV__, test, [])
|
||||
def unquote(test)(unquote(var)), do: unquote(contents)
|
||||
end
|
||||
end
|
||||
@@ -284,6 +281,12 @@ defmodule ExUnit.Case do
|
||||
@doc false
|
||||
defmacro __before_compile__(_) do
|
||||
quote do
|
||||
if @ex_unit_async do
|
||||
ExUnit.Server.add_async_case(__MODULE__)
|
||||
else
|
||||
ExUnit.Server.add_sync_case(__MODULE__)
|
||||
end
|
||||
|
||||
def __ex_unit__(:case) do
|
||||
%ExUnit.TestCase{name: __MODULE__, tests: @ex_unit_tests}
|
||||
end
|
||||
@@ -291,8 +294,7 @@ defmodule ExUnit.Case do
|
||||
end
|
||||
|
||||
@doc false
|
||||
def __on_definition__(env, name, tags \\ []) do
|
||||
mod = env.module
|
||||
def __on_definition__(%{module: mod, file: file, line: line}, name, tags) do
|
||||
moduletag = Module.get_attribute(mod, :moduletag)
|
||||
|
||||
unless moduletag do
|
||||
@@ -304,7 +306,7 @@ defmodule ExUnit.Case do
|
||||
(tags ++ Module.get_attribute(mod, :tag) ++ moduletag)
|
||||
|> normalize_tags
|
||||
|> validate_tags
|
||||
|> Map.merge(%{line: env.line, file: env.file})
|
||||
|> Map.merge(%{line: line, file: file})
|
||||
|
||||
test = %ExUnit.Test{name: name, case: mod, tags: tags}
|
||||
test_names = Module.get_attribute(mod, :ex_unit_test_names)
|
||||
|
||||
@@ -11,6 +11,16 @@ alias ExUnit.AssertionsTest.Value
|
||||
defmodule ExUnit.AssertionsTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
defmacrop assert_ok(arg) do
|
||||
quote do
|
||||
assert {:ok, val} = ok(unquote(arg))
|
||||
end
|
||||
end
|
||||
|
||||
test "assert inside macro" do
|
||||
assert_ok 42
|
||||
end
|
||||
|
||||
test "assert with true value" do
|
||||
true = assert Value.truthy
|
||||
end
|
||||
|
||||
@@ -152,7 +152,7 @@ defmodule ExUnitTest do
|
||||
refute output =~ "[debug] four"
|
||||
end
|
||||
|
||||
test "it supports multi errors" do
|
||||
test "supports multi errors" do
|
||||
capture_io :stderr, fn ->
|
||||
defmodule MultiTest do
|
||||
use ExUnit.Case
|
||||
@@ -187,7 +187,7 @@ defmodule ExUnitTest do
|
||||
assert output =~ "Failure #2"
|
||||
end
|
||||
|
||||
test "it registers only the first test with any given name" do
|
||||
test "registers only the first test with any given name" do
|
||||
capture_io :stderr, fn ->
|
||||
defmodule TestWithSameNames do
|
||||
use ExUnit.Case
|
||||
@@ -207,7 +207,7 @@ defmodule ExUnitTest do
|
||||
end) =~ "1 test, 0 failure"
|
||||
end
|
||||
|
||||
test "it produces error on not implemented tests" do
|
||||
test "produces error on not implemented tests" do
|
||||
defmodule TestNotImplemented do
|
||||
use ExUnit.Case
|
||||
|
||||
@@ -227,7 +227,7 @@ defmodule ExUnitTest do
|
||||
assert output =~ "1 test, 1 failure"
|
||||
end
|
||||
|
||||
test "it skips tagged test with skip" do
|
||||
test "skips tagged test with skip" do
|
||||
defmodule TestSkipped do
|
||||
use ExUnit.Case
|
||||
|
||||
@@ -250,6 +250,55 @@ defmodule ExUnitTest do
|
||||
assert output =~ "2 tests, 0 failures, 2 skipped"
|
||||
end
|
||||
|
||||
test "raises on reserved tag in module" do
|
||||
assert_raise RuntimeError, "cannot set tag :file because it is reserved by ExUnit", fn ->
|
||||
defmodule ReservedTag do
|
||||
use ExUnit.Case
|
||||
|
||||
setup do
|
||||
{:ok, file: :foo}
|
||||
end
|
||||
|
||||
@tag file: "oops"
|
||||
test "sample", do: :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "raises on reserved tag in setup" do
|
||||
defmodule ReservedSetupTag do
|
||||
use ExUnit.Case
|
||||
|
||||
setup do
|
||||
{:ok, file: :foo}
|
||||
end
|
||||
|
||||
test "sample", do: :ok
|
||||
end
|
||||
|
||||
output = capture_io(fn ->
|
||||
assert ExUnit.run == %{failures: 1, skipped: 0, total: 1}
|
||||
end)
|
||||
|
||||
assert output =~ "trying to set reserved field :file"
|
||||
end
|
||||
|
||||
test "does not raise on reserved tag in setup_all (lower priority)" do
|
||||
defmodule ReservedSetupAllTag do
|
||||
use ExUnit.Case
|
||||
|
||||
setup_all do
|
||||
{:ok, file: :foo}
|
||||
end
|
||||
|
||||
test "sample", do: :ok
|
||||
end
|
||||
|
||||
capture_io(fn ->
|
||||
assert ExUnit.run == %{failures: 0, skipped: 0, total: 1}
|
||||
end)
|
||||
end
|
||||
|
||||
defp run_with_filter(filters, {async, sync, load_us}) do
|
||||
opts = Keyword.merge(ExUnit.configuration, filters)
|
||||
output = capture_io fn ->
|
||||
|
||||
@@ -63,6 +63,7 @@ defmodule IEx.Config do
|
||||
defp default_option(:colors), do: [{:enabled, IO.ANSI.enabled?} | default_colors()]
|
||||
defp default_option(:inspect), do: []
|
||||
defp default_option(:history_size), do: 20
|
||||
defp default_option(:width), do: width()
|
||||
|
||||
defp default_option(prompt) when prompt in [:default_prompt, :alive_prompt] do
|
||||
"%prefix(%counter)>"
|
||||
|
||||
@@ -27,9 +27,9 @@ defmodule IEx.Helpers do
|
||||
* `cd/1` - changes the current directory
|
||||
* `clear/0` - clears the screen
|
||||
* `flush/0` - flushes all messages sent to the shell
|
||||
* `i/1` - prints information about the given data type
|
||||
* `h/0` - prints this help message
|
||||
* `h/1` - prints help for the given module, function or macro
|
||||
* `i/1` - prints information about the given data type
|
||||
* `import_file/1` - evaluates the given file in the shell's context
|
||||
* `l/1` - loads the given module's beam code
|
||||
* `ls/0` - lists the contents of the current directory
|
||||
@@ -42,7 +42,6 @@ defmodule IEx.Helpers do
|
||||
* `t/1` — prints type information
|
||||
* `v/0` — retrieves the last value from the history
|
||||
* `v/1` — retrieves the nth value from the history
|
||||
* `import_file/1` — evaluates the given file in the shell's context
|
||||
|
||||
Help for all of those functions can be consulted directly from
|
||||
the command line using the `h` helper itself. Try:
|
||||
|
||||
+11
-9
@@ -227,13 +227,14 @@ defimpl IEx.Info, for: PID do
|
||||
|
||||
def info(pid) do
|
||||
extra =
|
||||
if info = Process.info(pid, @keys) do
|
||||
["Alive": true,
|
||||
"Name": process_name(info[:registered_name]),
|
||||
"Links": links(info[:links]),
|
||||
"Message queue length": info[:message_queue_len]]
|
||||
else
|
||||
["Alive": false]
|
||||
case :rpc.pinfo(pid, @keys) do
|
||||
[_|_] = info ->
|
||||
["Alive": true,
|
||||
"Name": process_name(info[:registered_name]),
|
||||
"Links": links(info[:links]),
|
||||
"Message queue length": info[:message_queue_len]]
|
||||
_ ->
|
||||
["Alive": false]
|
||||
end
|
||||
|
||||
["Data type": "PID"] ++ extra ++
|
||||
@@ -257,9 +258,10 @@ end
|
||||
|
||||
defimpl IEx.Info, for: Port do
|
||||
def info(port) do
|
||||
port_info = Port.info(port)
|
||||
connected = :rpc.call(node(port), :erlang, :port_info, [port, :connected])
|
||||
|
||||
["Data type": "Port",
|
||||
"Open": port_info != nil,
|
||||
"Open": match?({:connected, _}, connected),
|
||||
"Reference modules": "Port"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Code.require_file "../test_helper.exs", __DIR__
|
||||
|
||||
defmodule IEx.ConfigTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
test "configuration sets a default for width" do
|
||||
assert IEx.Config.configuration[:width] == 80
|
||||
end
|
||||
end
|
||||
@@ -137,29 +137,26 @@ defmodule Mix.Compilers.Elixir do
|
||||
|> List.delete(module)
|
||||
|> Enum.reject(&match?("elixir_" <> _, Atom.to_string(&1)))
|
||||
|
||||
attributes = module.__info__(:attributes)
|
||||
|
||||
kind = detect_kind(attributes)
|
||||
kind = detect_kind(module)
|
||||
source = Path.relative_to(source, cwd)
|
||||
files = get_external_resources(attributes, cwd)
|
||||
files = get_external_resources(module, cwd)
|
||||
tuple = {beam, module, kind, source, compile, runtime, files, binary}
|
||||
Agent.cast pid, &:lists.keystore(beam, 1, &1, tuple)
|
||||
end
|
||||
|
||||
defp detect_kind(attributes) do
|
||||
defp detect_kind(module) do
|
||||
cond do
|
||||
impl = attributes[:impl] ->
|
||||
impl = Module.get_attribute(module, :impl) ->
|
||||
{:impl, impl[:protocol]}
|
||||
attributes[:protocol] ->
|
||||
Module.get_attribute(module, :protocol) ->
|
||||
:protocol
|
||||
true ->
|
||||
:module
|
||||
end
|
||||
end
|
||||
|
||||
defp get_external_resources(attributes, cwd) do
|
||||
for {:external_resource, values} <- attributes,
|
||||
file <- values,
|
||||
defp get_external_resources(module, cwd) do
|
||||
for file <- Module.get_attribute(module, :external_resource),
|
||||
File.regular?(file),
|
||||
relative = Path.relative_to(file, cwd),
|
||||
Path.type(relative) == :relative,
|
||||
|
||||
+30
-3
@@ -100,9 +100,12 @@ defmodule Mix.Dep do
|
||||
|
||||
# Ensure all apps are atoms
|
||||
apps = to_app_names(given)
|
||||
|
||||
# We need to keep the order of deps, loaded/1 properly orders them
|
||||
deps = Enum.filter(all_deps, &(&1.app in apps))
|
||||
deps =
|
||||
if opts[:include_children] do
|
||||
get_deps_with_children(all_deps, apps)
|
||||
else
|
||||
get_deps(all_deps, apps)
|
||||
end
|
||||
|
||||
Enum.each apps, fn(app) ->
|
||||
unless Enum.any?(all_deps, &(&1.app == app)) do
|
||||
@@ -113,6 +116,30 @@ defmodule Mix.Dep do
|
||||
deps
|
||||
end
|
||||
|
||||
defp get_deps(all_deps, apps) do
|
||||
Enum.filter(all_deps, &(&1.app in apps))
|
||||
end
|
||||
|
||||
defp get_deps_with_children(all_deps, apps) do
|
||||
deps = get_children(all_deps, apps)
|
||||
apps = deps |> Enum.map(& &1.app) |> Enum.uniq
|
||||
get_deps(all_deps, apps)
|
||||
end
|
||||
|
||||
defp get_children(_all_deps, []), do: []
|
||||
defp get_children(all_deps, apps) do
|
||||
# Current deps
|
||||
deps = get_deps(all_deps, apps)
|
||||
|
||||
# Children apps
|
||||
apps = for %{deps: children} <- deps,
|
||||
%{app: app} <- children,
|
||||
do: app
|
||||
|
||||
# Current deps + children deps
|
||||
deps ++ get_children(all_deps, apps)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Runs the given `fun` inside the given dependency project by
|
||||
changing the current working directory and loading the given
|
||||
|
||||
@@ -49,16 +49,12 @@ defmodule Mix.Dep.Converger do
|
||||
end
|
||||
|
||||
defp all(acc, lock, opts, callback) do
|
||||
deps = Mix.Dep.Loader.children()
|
||||
deps = Enum.map(deps, &(%{&1 | top_level: true}))
|
||||
lock_given? = !!lock
|
||||
main = Mix.Dep.Loader.children()
|
||||
main = Enum.map(main, &(%{&1 | top_level: true}))
|
||||
apps = Enum.map(main, &(&1.app))
|
||||
|
||||
# Filter the dependencies per environment. We pass the ones
|
||||
# left out as accumulator and upper breadth to help catch
|
||||
# inconsistencies across environment, specially regarding
|
||||
# the :only option. They are filtered again later.
|
||||
current = Enum.map(deps, &(&1.app))
|
||||
{main, only} = Mix.Dep.Loader.partition_by_env(deps, opts)
|
||||
lock_given? = !!lock
|
||||
env = opts[:env]
|
||||
|
||||
# If no lock was given, let's read one to fill in the deps
|
||||
lock = lock || Mix.Dep.Lock.read
|
||||
@@ -68,7 +64,7 @@ defmodule Mix.Dep.Converger do
|
||||
# lazily loaded, we need to check for it on every
|
||||
# iteration.
|
||||
{deps, rest, lock} =
|
||||
all(main, only, [], current, callback, acc, lock, fn dep ->
|
||||
all(main, apps, callback, acc, lock, env, fn dep ->
|
||||
if (remote = Mix.RemoteConverger.get) && remote.remote?(dep) do
|
||||
{:loaded, dep}
|
||||
else
|
||||
@@ -76,9 +72,6 @@ defmodule Mix.Dep.Converger do
|
||||
end
|
||||
end)
|
||||
|
||||
# Filter deps per environment once more. If the filtered
|
||||
# dependencies had no conflicts, they are removed now.
|
||||
{deps, _} = Mix.Dep.Loader.partition_by_env(deps, opts)
|
||||
diverged? = Enum.any?(deps, &Mix.Dep.diverged?/1)
|
||||
|
||||
# Run remote converger if one is available and rerun Mix's
|
||||
@@ -99,19 +92,29 @@ defmodule Mix.Dep.Converger do
|
||||
# In case no lock was given, we will use the local lock
|
||||
# which is potentially stale. So remote.deps/2 needs to always
|
||||
# check if the data it finds in the lock is actually valid.
|
||||
all(main, [], [], Enum.map(main, &(&1.app)), callback, rest, lock, fn dep ->
|
||||
cond do
|
||||
cached = deps[dep.app] ->
|
||||
{deps, rest, lock} =
|
||||
all(main, apps, callback, rest, lock, env, fn dep ->
|
||||
if cached = deps[dep.app] do
|
||||
{:loaded, cached}
|
||||
true ->
|
||||
else
|
||||
{:unloaded, dep, remote.deps(dep, lock)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
{reject_non_fullfilled_optional(deps), rest, lock}
|
||||
else
|
||||
{deps, rest, lock}
|
||||
{reject_non_fullfilled_optional(deps), rest, lock}
|
||||
end
|
||||
end
|
||||
|
||||
defp all(main, apps, callback, rest, lock, env, cache) do
|
||||
{deps, rest, lock} = all(main, [], [], apps, callback, rest, lock, env, cache)
|
||||
# When traversing dependencies, we keep skipped ones to
|
||||
# find conflicts. We remove them now after traversal.
|
||||
{deps, _} = Mix.Dep.Loader.partition_by_env(deps, env)
|
||||
{deps, rest, lock}
|
||||
end
|
||||
|
||||
# We traverse the tree of dependencies in a breadth-first
|
||||
# fashion. The reason for this is that we converge
|
||||
# dependencies, but allow the parent to override any
|
||||
@@ -151,10 +154,14 @@ defmodule Mix.Dep.Converger do
|
||||
# Now, since "d" was specified in a parent project, no
|
||||
# exception is going to be raised since d is considered
|
||||
# to be the authoritative source.
|
||||
defp all([dep|t], acc, upper_breadths, current_breadths, callback, rest, lock, cache) do
|
||||
defp all([dep|t], acc, upper_breadths, current_breadths, callback, rest, lock, env, cache) do
|
||||
cond do
|
||||
new_acc = diverged_deps(acc, upper_breadths, dep) ->
|
||||
all(t, new_acc, upper_breadths, current_breadths, callback, rest, lock, cache)
|
||||
all(t, new_acc, upper_breadths, current_breadths, callback, rest, lock, env, cache)
|
||||
Mix.Dep.Loader.skip?(dep, env) ->
|
||||
# We still keep skipped dependencies around to detect conflicts.
|
||||
# They must be rejected after every all iteration.
|
||||
all(t, [dep|acc], upper_breadths, current_breadths, callback, rest, lock, env, cache)
|
||||
true ->
|
||||
dep =
|
||||
case cache.(dep) do
|
||||
@@ -169,13 +176,16 @@ defmodule Mix.Dep.Converger do
|
||||
Mix.Dep.Loader.load(dep, children)
|
||||
end
|
||||
|
||||
dep = %{dep | deps: reject_non_fullfilled_optional(dep.deps, current_breadths)}
|
||||
{acc, rest, lock} = all(t, [dep|acc], upper_breadths, current_breadths, callback, rest, lock, cache)
|
||||
all(dep.deps, acc, current_breadths, Enum.map(dep.deps, &(&1.app)) ++ current_breadths, callback, rest, lock, cache)
|
||||
{acc, rest, lock} =
|
||||
all(t, [dep|acc], upper_breadths, current_breadths, callback, rest, lock, env, cache)
|
||||
|
||||
deps = reject_non_fullfilled_optional(dep.deps, current_breadths)
|
||||
new_breadths = Enum.map(deps, &(&1.app)) ++ current_breadths
|
||||
all(deps, acc, current_breadths, new_breadths, callback, rest, lock, env, cache)
|
||||
end
|
||||
end
|
||||
|
||||
defp all([], acc, _upper, _current, _callback, rest, lock, _cache) do
|
||||
defp all([], acc, _upper, _current, _callback, rest, lock, _env, _cache) do
|
||||
{acc, rest, lock}
|
||||
end
|
||||
|
||||
@@ -206,7 +216,8 @@ defmodule Mix.Dep.Converger do
|
||||
in_upper? && other_opts[:override] ->
|
||||
{other |> with_matching_only(dep, in_upper?), true}
|
||||
converge?(other, dep) ->
|
||||
{other |> with_matching_only(dep, in_upper?) |> with_matching_req(dep) |> merge_manager(dep), true}
|
||||
{other |> with_matching_only(dep, in_upper?)
|
||||
|> with_matching_req(dep) |> merge_manager(dep, in_upper?), true}
|
||||
true ->
|
||||
tag = if in_upper?, do: :overridden, else: :diverged
|
||||
{%{other | status: {tag, dep}}, true}
|
||||
@@ -269,32 +280,40 @@ defmodule Mix.Dep.Converger do
|
||||
end
|
||||
end
|
||||
|
||||
defp converge?(%Mix.Dep{scm: scm1, manager: manager1, opts: opts1},
|
||||
%Mix.Dep{scm: scm2, manager: manager2, opts: opts2}) do
|
||||
scm1 == scm2 and
|
||||
manager_equal?(manager1, manager2) and
|
||||
opts_equal?(opts1, opts2) and
|
||||
scm1.equal?(opts1, opts2)
|
||||
defp converge?(%Mix.Dep{scm: scm1, opts: opts1}, %Mix.Dep{scm: scm2, opts: opts2}) do
|
||||
scm1 == scm2 and opts_equal?(opts1, opts2) and scm1.equal?(opts1, opts2)
|
||||
end
|
||||
|
||||
defp manager_equal?(manager, manager), do: true
|
||||
defp manager_equal?(_, nil), do: true
|
||||
defp manager_equal?(nil, _), do: true
|
||||
defp manager_equal?(_, _), do: false
|
||||
|
||||
defp opts_equal?(opts1, opts2) do
|
||||
keys = ~w(app env compile)a
|
||||
Enum.all?(keys, &(Keyword.fetch(opts1, &1) == Keyword.fetch(opts2, &1)))
|
||||
end
|
||||
|
||||
defp reject_non_fullfilled_optional(deps) do
|
||||
apps = Enum.map(deps, & &1.app)
|
||||
for dep <- deps do
|
||||
update_in dep.deps, &reject_non_fullfilled_optional(&1, apps)
|
||||
end
|
||||
end
|
||||
|
||||
defp reject_non_fullfilled_optional(children, upper_breadths) do
|
||||
Enum.reject children, fn %Mix.Dep{app: app, opts: opts} ->
|
||||
opts[:optional] && not(app in upper_breadths)
|
||||
end
|
||||
end
|
||||
|
||||
defp merge_manager(other, dep) do
|
||||
%{other | manager: other.manager || dep.manager}
|
||||
defp merge_manager(%{manager: other_manager} = other, %{manager: manager}, in_upper?) do
|
||||
%{other | manager: sort_manager(other_manager, manager, in_upper?)}
|
||||
end
|
||||
|
||||
@managers [:mix, :rebar3, :rebar, :make]
|
||||
|
||||
defp sort_manager(other_manager, manager, true) do
|
||||
other_manager || manager
|
||||
end
|
||||
defp sort_manager(other_manager, manager, false) do
|
||||
priority = @managers -- (@managers -- (List.wrap(other_manager) ++ List.wrap(manager)))
|
||||
List.first(priority) || other_manager || manager
|
||||
end
|
||||
|
||||
defp with_matching_req(%Mix.Dep{} = other, %Mix.Dep{} = dep) do
|
||||
|
||||
@@ -96,9 +96,7 @@ defmodule Mix.Dep.Fetcher do
|
||||
# it for compilation too, this is our best to try to solve the
|
||||
# maximum we can at each deps.get and deps.update.
|
||||
if Enum.all?(all_deps, &available?/1) do
|
||||
deps = (with_depending(deps, all_deps) ++
|
||||
Enum.filter(all_deps, fn dep -> not ok?(dep) end))
|
||||
|> Enum.uniq(&(&1.app))
|
||||
deps = Enum.uniq_by(with_depending(deps, all_deps), &(&1.app))
|
||||
end
|
||||
|
||||
# Merge the new lock on top of the old to guarantee we don't
|
||||
|
||||
@@ -21,18 +21,18 @@ defmodule Mix.Dep.Loader do
|
||||
@doc """
|
||||
Partitions loaded dependencies by environment.
|
||||
"""
|
||||
def partition_by_env(deps, opts) do
|
||||
if env = opts[:env] do
|
||||
Enum.partition(deps, fn
|
||||
%Mix.Dep{status: {:divergedonly, _}} ->
|
||||
true
|
||||
%Mix.Dep{opts: opts} ->
|
||||
only = opts[:only] |> List.wrap |> validate_only!
|
||||
only == [] or env in List.wrap(only)
|
||||
end)
|
||||
else
|
||||
{deps, []}
|
||||
end
|
||||
def partition_by_env(deps, nil), do: {deps, []}
|
||||
def partition_by_env(deps, env), do: Enum.partition(deps, ¬ skip?(&1, env))
|
||||
|
||||
@doc """
|
||||
Check if a dependency must be skipped according to the environment.
|
||||
"""
|
||||
def skip?(_dep, nil), do: false
|
||||
def skip?(%Mix.Dep{status: {:divergedonly, _}}, _), do: false
|
||||
def skip?(%Mix.Dep{opts: opts}, env) do
|
||||
only = opts[:only]
|
||||
validate_only!(only)
|
||||
only != nil and not env in List.wrap(only)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -283,7 +283,7 @@ defmodule Mix.Dep.Loader do
|
||||
end
|
||||
|
||||
defp validate_only!(only) do
|
||||
for entry <- only, not is_atom(entry) do
|
||||
for entry <- List.wrap(only), not is_atom(entry) do
|
||||
Mix.raise "Expected :only in dependency to be an atom or a list of atoms, got: #{inspect only}"
|
||||
end
|
||||
only
|
||||
@@ -293,7 +293,7 @@ defmodule Mix.Dep.Loader do
|
||||
from = Path.absname("mix.exs")
|
||||
(Mix.Project.config[:deps] || [])
|
||||
|> Enum.map(&to_dep(&1, from))
|
||||
|> partition_by_env(opts)
|
||||
|> partition_by_env(opts[:env])
|
||||
|> elem(0)
|
||||
end
|
||||
|
||||
|
||||
@@ -236,6 +236,22 @@ defmodule Mix.Project do
|
||||
Path.expand config[:deps_path]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the full path of all dependencies as a map.
|
||||
|
||||
## Examples
|
||||
|
||||
Mix.Project.deps_paths
|
||||
#=> %{foo: "deps/foo", bar: "custom/path/dep"}
|
||||
|
||||
"""
|
||||
@spec deps_paths() :: %{atom => Path.t}
|
||||
def deps_paths do
|
||||
Enum.reduce Mix.Dep.loaded(env: Mix.env), %{}, fn
|
||||
%{app: app, opts: opts}, acc -> Map.put acc, app, opts[:dest]
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the build path for this project.
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ defmodule Mix.Tasks.App.Start do
|
||||
* `--permanent` - start the application as permanent
|
||||
* `--no-compile` - do not compile even if files require compilation
|
||||
* `--no-protocols` - do not load consolidated protocols
|
||||
* `--no-archives-check` - do not check archives
|
||||
* `--no-deps-check` - do not check dependencies
|
||||
* `--no-elixir-version-check` - do not check Elixir version
|
||||
* `--no-start` - do not start applications after compilation
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
defmodule Mix.Tasks.Archive.Check do
|
||||
use Mix.Task
|
||||
|
||||
@moduledoc """
|
||||
Checks all archives are available.
|
||||
|
||||
Mix projects can specify required archives using
|
||||
the `:archives` option:
|
||||
|
||||
archives: [{:foo, "~> 1.0.0"}]
|
||||
|
||||
This task guarantees this option is respected.
|
||||
"""
|
||||
def run(_) do
|
||||
archives = Mix.Project.config[:archives] || []
|
||||
|
||||
Enum.each archives, fn tuple ->
|
||||
{archive, req} = parse_archive(tuple)
|
||||
_ = Application.load(archive)
|
||||
vsn = Application.spec(archive, :vsn)
|
||||
cond do
|
||||
is_nil(vsn) ->
|
||||
Mix.raise "Archive \"#{archive}\" could not be found. " <>
|
||||
"Please make sure the archive is installed locally."
|
||||
not Version.match?(List.to_string(vsn), req) ->
|
||||
Mix.raise "Archive \"#{archive}-#{vsn}\" does not match requirement #{req}. " <>
|
||||
"Please update your archive version accordingly."
|
||||
true ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_archive({archive, req}) when is_atom(archive) and is_binary(req) do
|
||||
case Version.parse_requirement(req) do
|
||||
{:ok, req} ->
|
||||
{archive, req}
|
||||
:error ->
|
||||
Mix.raise "Invalid requirement #{req} for archive \"#{archive}\""
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_archive(other) do
|
||||
Mix.raise """
|
||||
Expected archive to be in the format:
|
||||
|
||||
{app :: atom, requirement :: binary}
|
||||
|
||||
got:
|
||||
|
||||
#{inspect other}
|
||||
|
||||
"""
|
||||
end
|
||||
end
|
||||
@@ -80,6 +80,12 @@ defmodule Mix.Tasks.Compile.Erlang do
|
||||
|
||||
Mix.Compilers.Erlang.compile(manifest(), tuples, fn
|
||||
input, _output ->
|
||||
# We're purging the module because a previous compiler (e.g. Phoenix)
|
||||
# might have already loaded the previous version of it.
|
||||
module = Path.basename(input, ".erl") |> String.to_atom
|
||||
:code.purge(module)
|
||||
:code.delete(module)
|
||||
|
||||
file = to_erl_file(Path.rootname(input, ".erl"))
|
||||
:compile.file(file, erlc_options)
|
||||
end)
|
||||
|
||||
@@ -41,9 +41,10 @@ defmodule Mix.Tasks.Compile do
|
||||
|
||||
## Command line options
|
||||
|
||||
* `--list` - list all enabled compilers
|
||||
* `--no-deps-check` - skip checking of dependencies
|
||||
* `--force` - force compilation
|
||||
* `--list` - list all enabled compilers
|
||||
* `--no-archives-check` - skip checking of archives
|
||||
* `--no-deps-check` - skip checking of dependencies
|
||||
* `--force` - force compilation
|
||||
|
||||
"""
|
||||
@spec run(OptionParser.argv) :: :ok | :noop
|
||||
@@ -127,8 +128,8 @@ defmodule Mix.Tasks.Compile do
|
||||
"""
|
||||
def manifests do
|
||||
Enum.flat_map(compilers(), fn(compiler) ->
|
||||
module = Mix.Task.get!("compile.#{compiler}")
|
||||
if function_exported?(module, :manifests, 0) do
|
||||
module = Mix.Task.get("compile.#{compiler}")
|
||||
if module && function_exported?(module, :manifests, 0) do
|
||||
module.manifests
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -14,10 +14,15 @@ defmodule Mix.Tasks.Deps.Check do
|
||||
## Command line options
|
||||
|
||||
* `--no-compile` - do not compile dependencies
|
||||
* `--no-archives-check` - do not check archives
|
||||
|
||||
"""
|
||||
@spec run(OptionParser.argv) :: :ok
|
||||
def run(args) do
|
||||
unless "--no-archives-check" in args do
|
||||
Mix.Task.run "archive.check", args
|
||||
end
|
||||
|
||||
all = Enum.map(loaded(env: Mix.env), &check_lock/1)
|
||||
|
||||
_ = prune_deps(all)
|
||||
|
||||
@@ -6,8 +6,8 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
@moduledoc """
|
||||
Compiles dependencies.
|
||||
|
||||
By default, compile all dependencies. A list of dependencies can
|
||||
be given to force the compilation of specific dependencies.
|
||||
By default, compile all dependencies. A list of dependencies
|
||||
can be given to force the compilation of specific dependencies.
|
||||
|
||||
This task attempts to detect if the project contains one of
|
||||
the following files and act accordingly:
|
||||
@@ -22,23 +22,35 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
|
||||
{:some_dependency, "0.1.0", compile: "command to compile"}
|
||||
|
||||
If a list of dependencies is given, Mix will attempt to compile
|
||||
them as is. For example, if project `a` depends on `b`, calling
|
||||
`mix deps.compile a` will compile `a` even if `b` is out of
|
||||
date. This is to allow parts of the dependency tree to be
|
||||
recompiled without propagating those changes upstream. To ensure
|
||||
`b` is included in the compilation step, pass `--include-children`.
|
||||
"""
|
||||
|
||||
import Mix.Dep, only: [loaded: 1, available?: 1, loaded_by_name: 2,
|
||||
format_dep: 1, make?: 1, mix?: 1, rebar?: 1]
|
||||
format_dep: 1, make?: 1, mix?: 1]
|
||||
|
||||
@switches [include_children: :boolean]
|
||||
|
||||
@spec run(OptionParser.argv) :: :ok
|
||||
def run(args) do
|
||||
unless "--no-archives-check" in args do
|
||||
Mix.Task.run "archive.check", args
|
||||
end
|
||||
|
||||
Mix.Project.get!
|
||||
|
||||
case OptionParser.parse(args) do
|
||||
case OptionParser.parse(args, switches: @switches) do
|
||||
{_, [], _} ->
|
||||
# Because this command is invoked explicitly with
|
||||
# Because this command may be invoked explicitly with
|
||||
# deps.compile, we simply try to compile any available
|
||||
# dependency.
|
||||
compile(Enum.filter(loaded(env: Mix.env), &available?/1))
|
||||
{_, tail, _} ->
|
||||
compile(loaded_by_name(tail, env: Mix.env))
|
||||
{opts, tail, _} ->
|
||||
compile(loaded_by_name(tail, [env: Mix.env] ++ opts))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -47,7 +59,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
shell = Mix.shell
|
||||
config = Mix.Project.deps_config
|
||||
|
||||
Mix.Task.run "deps.loadpaths"
|
||||
Mix.Task.run "deps.precompile"
|
||||
|
||||
compiled =
|
||||
Enum.map(deps, fn %Mix.Dep{app: app, status: status, opts: opts, scm: scm} = dep ->
|
||||
@@ -100,6 +112,11 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
"but you are running on v#{System.version}"
|
||||
end
|
||||
|
||||
# Force recompilation on compile status
|
||||
if dep.status == :compile do
|
||||
Mix.Dep.Lock.touch_manifest
|
||||
end
|
||||
|
||||
try do
|
||||
res = Mix.Task.run("compile", ["--no-deps", "--no-elixir-version-check"])
|
||||
:ok in List.wrap(res)
|
||||
|
||||
@@ -9,10 +9,15 @@ defmodule Mix.Tasks.Deps.Get do
|
||||
|
||||
## Command line options
|
||||
|
||||
* `--only` - only fetch dependencies for given environment
|
||||
* `--only` - only fetch dependencies for given environment
|
||||
* `--no-archives-check` - do not check archives before fetching deps
|
||||
"""
|
||||
@spec run(OptionParser.argv) :: :ok
|
||||
def run(args) do
|
||||
unless "--no-archives-check" in args do
|
||||
Mix.Task.run "archive.check", args
|
||||
end
|
||||
|
||||
Mix.Project.get!
|
||||
{opts, _, _} = OptionParser.parse(args, switches: [only: :string])
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
defmodule Mix.Tasks.Deps.Precompile do
|
||||
use Mix.Task
|
||||
|
||||
@moduledoc """
|
||||
Extension point for precompiling dependencies.
|
||||
|
||||
This is a task that can be aliased by projects
|
||||
that need to execute certain tasks to before
|
||||
compiling dependencies:
|
||||
|
||||
aliases: ["deps.precompile": ["nerves.precompile", "deps.precompile"]]
|
||||
|
||||
By default, this task has a single responsibility
|
||||
of loading all dependencies paths.
|
||||
"""
|
||||
def run(_) do
|
||||
Mix.Task.run "deps.loadpaths"
|
||||
end
|
||||
end
|
||||
@@ -13,11 +13,15 @@ defmodule Mix.Tasks.Deps.Update do
|
||||
|
||||
## Command line options
|
||||
|
||||
* `--all` - update all dependencies
|
||||
* `--all` - update all dependencies
|
||||
* `--only` - only fetch dependencies for given environment
|
||||
* `--no-archives-check` - do not check archives before fetching deps
|
||||
"""
|
||||
@spec run(OptionParser.argv) :: [atom]
|
||||
def run(args) do
|
||||
unless "--no-archives-check" in args do
|
||||
Mix.Task.run "archive.check", args
|
||||
end
|
||||
Mix.Project.get!
|
||||
{opts, rest, _} = OptionParser.parse(args, switches: [all: :boolean, only: :string])
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ defmodule Mix.Tasks.Loadpaths do
|
||||
|
||||
## Command line options
|
||||
|
||||
* `--no-deps-check` - do not check dependencies
|
||||
* `--no-archives-check` - do not check archive
|
||||
* `--no-deps-check` - do not check dependencies (also implies --no-archives-check)
|
||||
* `--no-elixir-version-check` - do not check Elixir version
|
||||
|
||||
"""
|
||||
|
||||
@@ -100,6 +100,11 @@ defmodule Mix.Tasks.Test do
|
||||
|
||||
mix test --only line:12 test/some/particular/file_test.exs
|
||||
|
||||
Note that line filter takes the closest test on or before the given line number.
|
||||
In the case a single file contains more than one test module (test case),
|
||||
line filter applies to every test case before the given line number, thus more
|
||||
than one test might be taken for the run.
|
||||
|
||||
## Configuration
|
||||
|
||||
* `:test_paths` - list of paths containing test files, defaults to
|
||||
|
||||
@@ -53,6 +53,17 @@ defmodule Mix.DepTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "extracts all dependencies paths from the given project" do
|
||||
Mix.Project.push DepsApp
|
||||
|
||||
in_fixture "deps_status", fn ->
|
||||
paths = Mix.Project.deps_paths
|
||||
assert map_size(paths) == 6
|
||||
assert paths[:ok] =~ "deps/ok"
|
||||
assert paths[:uncloned] =~ "deps/uncloned"
|
||||
end
|
||||
end
|
||||
|
||||
test "fails on invalid dependencies" do
|
||||
assert_wrong_dependency [{:ok}]
|
||||
assert_wrong_dependency [{:ok, nil}]
|
||||
@@ -144,7 +155,22 @@ defmodule Mix.DepTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "nested deps convergence with optional dependencies" do
|
||||
test "nested deps with convergence and managers" do
|
||||
Process.put(:custom_deps_git_repo_opts, [manager: :make])
|
||||
|
||||
deps = [{:deps_repo, "0.1.0", path: "custom/deps_repo", manager: :rebar},
|
||||
{:git_repo, "0.2.0", git: MixTest.Case.fixture_path("git_repo")}]
|
||||
|
||||
with_deps deps, fn ->
|
||||
in_fixture "deps_status", fn ->
|
||||
[dep1, dep2] = Mix.Dep.loaded([])
|
||||
assert dep1.manager == nil
|
||||
assert dep2.manager == :rebar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "nested deps with convergence and optional dependencies" do
|
||||
deps = [{:deps_repo, "0.1.0", path: "custom/deps_repo"},
|
||||
{:git_repo, "0.2.0", git: MixTest.Case.fixture_path("git_repo")}]
|
||||
|
||||
@@ -255,9 +281,8 @@ defmodule Mix.DepTest do
|
||||
deps = Mix.Dep.loaded([])
|
||||
assert length(deps) == 2
|
||||
|
||||
deps = Mix.Dep.loaded([env: :prod])
|
||||
assert length(deps) == 1
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :foo}, &1)
|
||||
assert [dep] = Mix.Dep.loaded([env: :prod])
|
||||
assert dep.app == :foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -132,6 +132,39 @@ defmodule Mix.Tasks.ArchiveTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "archive check" do
|
||||
# Install the archive
|
||||
in_fixture "archive", fn() ->
|
||||
Mix.Tasks.Archive.Build.run ["--no-elixir-version-check"]
|
||||
send self, {:mix_shell_input, :yes?, true}
|
||||
Mix.Tasks.Archive.Install.run []
|
||||
end
|
||||
|
||||
assert_raise Mix.Error, ~r/Expected archive to be in the format/, fn ->
|
||||
archive_check [:archive]
|
||||
end
|
||||
|
||||
assert_raise Mix.Error, ~r/Archive "archive" could not be found/, fn ->
|
||||
archive_check [{:archive, ">= 1.0.0"}]
|
||||
end
|
||||
|
||||
# Load the archive
|
||||
Mix.Local.append_archives
|
||||
|
||||
assert_raise Mix.Error, ~r/Archive \"archive-0.1.0\" does not match requirement >= 1.0.0/, fn ->
|
||||
archive_check [{:archive, ">= 1.0.0"}]
|
||||
end
|
||||
|
||||
archive_check [{:archive, ">= 0.0.0"}]
|
||||
end
|
||||
|
||||
defp archive_check(archives) do
|
||||
Mix.Project.pop
|
||||
Mix.ProjectStack.post_config archives: archives
|
||||
Mix.Project.push MixTest.Case.Sample
|
||||
Mix.Tasks.Archive.Check.run([])
|
||||
end
|
||||
|
||||
defp sha512(file) do
|
||||
Base.encode16 :crypto.hash(:sha512, File.read!(file)), case: :lower
|
||||
end
|
||||
|
||||
@@ -59,4 +59,25 @@ defmodule Mix.Tasks.Compile.ErlangTest do
|
||||
refute File.regular?("_build/dev/lib/sample/ebin/b.beam")
|
||||
end
|
||||
end
|
||||
|
||||
test "compilation purges the module" do
|
||||
in_fixture "compile_erlang", fn ->
|
||||
# Create the first version of the module.
|
||||
defmodule :purge_test do
|
||||
def version, do: :v1
|
||||
end
|
||||
assert :v1 == :purge_test.version
|
||||
|
||||
# Create the second version of the module (this time as Erlang source).
|
||||
File.write! "src/purge_test.erl", """
|
||||
-module(purge_test).
|
||||
-compile(export_all).
|
||||
version() -> v2.
|
||||
"""
|
||||
assert Mix.Tasks.Compile.Erlang.run([]) == :ok
|
||||
|
||||
# If the module was not purged on recompilation, this would fail.
|
||||
assert :v2 == :purge_test.version
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,6 +26,12 @@ defmodule Mix.Tasks.CompileTest do
|
||||
assert_received {:mix_shell, :info, ["\nEnabled compilers: elixir, app, custom, protocols"]}
|
||||
end
|
||||
|
||||
test "compile does not require all compilers available on manifest" do
|
||||
Mix.Project.push CustomCompilers
|
||||
assert Mix.Tasks.Compile.manifests |> Enum.map(&Path.basename/1) ==
|
||||
[".compile.elixir"]
|
||||
end
|
||||
|
||||
test "compile a project with mixfile" do
|
||||
in_fixture "no_mixfile", fn ->
|
||||
assert Mix.Tasks.Compile.run([]) == :ok
|
||||
|
||||
@@ -133,6 +133,23 @@ defmodule Mix.Tasks.DepsGitTest do
|
||||
purge [GitRepo, GitRepo.Mixfile]
|
||||
end
|
||||
|
||||
test "compiles many levels deep dependencies" do
|
||||
Mix.Project.push DepsOnGitApp
|
||||
|
||||
in_fixture "no_mixfile", fn ->
|
||||
Mix.Tasks.Deps.Get.run []
|
||||
refute File.exists?("_build/dev/lib/deps_on_git_repo")
|
||||
refute File.exists?("_build/dev/lib/git_repo")
|
||||
|
||||
# Compile the parent with children
|
||||
Mix.Tasks.Deps.Compile.run ["deps_on_git_repo", "--include-children"]
|
||||
assert File.exists?("_build/dev/lib/deps_on_git_repo")
|
||||
assert File.exists?("_build/dev/lib/git_repo")
|
||||
end
|
||||
after
|
||||
purge [GitRepo, GitRepo.Mixfile]
|
||||
end
|
||||
|
||||
test "recompiles the project when a dep is fetched" do
|
||||
Mix.Project.push GitApp
|
||||
|
||||
@@ -146,9 +163,6 @@ defmodule Mix.Tasks.DepsGitTest do
|
||||
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
|
||||
|
||||
# Clear up to prepare for the update
|
||||
File.rm("_build/dev/lib/git_repo/ebin/Elixir.GitRepo.beam")
|
||||
File.rm("_build/dev/lib/git_repo/.compile.elixir")
|
||||
File.rm("deps/git_repo/.fetch")
|
||||
Mix.Task.clear
|
||||
Mix.shell.flush
|
||||
purge [A, B, C, GitRepo]
|
||||
|
||||
@@ -113,15 +113,19 @@ defmodule Mix.UmbrellaTest do
|
||||
end
|
||||
"""
|
||||
|
||||
# Should work across all environments
|
||||
# Does not fetch when filtered
|
||||
Mix.Tasks.Deps.Get.run ["--only", "dev"]
|
||||
refute_received {:mix_shell, :info, ["* Getting git_repo" <> _]}
|
||||
|
||||
# But works across all environments
|
||||
Mix.Tasks.Deps.Get.run []
|
||||
assert_received {:mix_shell, :info, ["* Getting git_repo" <> _]}
|
||||
|
||||
# Works on the current environment only
|
||||
# Does not show by default
|
||||
Mix.Tasks.Deps.run []
|
||||
refute_received {:mix_shell, :info, ["* git_repo " <> _]}
|
||||
refute_received {:mix_shell, :info, ["* git_repo" <> _]}
|
||||
|
||||
# Works on the other environment only
|
||||
# But shows on proper environment
|
||||
Mix.env(:other)
|
||||
Mix.Tasks.Deps.run []
|
||||
assert_received {:mix_shell, :info, ["* git_repo " <> _]}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{application, elixir,
|
||||
[{description, "elixir"},
|
||||
{vsn, "1.2.0"},
|
||||
{vsn, "1.2.4"},
|
||||
{modules, [
|
||||
elixir
|
||||
]},
|
||||
|
||||
Reference in New Issue
Block a user