diff options
-rw-r--r-- | docs/api/admin_api.md | 15 | ||||
-rw-r--r-- | lib/mix/tasks/pleroma/config.ex | 6 | ||||
-rw-r--r-- | lib/pleroma/config/transfer_task.ex | 19 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/admin_api_controller.ex | 8 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/config.ex | 88 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/views/config_view.ex | 1 | ||||
-rw-r--r-- | lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex | 35 | ||||
-rw-r--r-- | priv/repo/migrations/20190622151019_add_group_key_to_config.exs | 12 | ||||
-rw-r--r-- | test/config/transfer_task_test.exs | 22 | ||||
-rw-r--r-- | test/fixtures/rich_media/non_ogp_embed.html | 1479 | ||||
-rw-r--r-- | test/fixtures/rich_media/ogp-missing-title.html | 12 | ||||
-rw-r--r-- | test/support/factory.ex | 1 | ||||
-rw-r--r-- | test/tasks/config_test.exs | 19 | ||||
-rw-r--r-- | test/web/activity_pub/mrf/anti_link_spam_policy_test.exs | 9 | ||||
-rw-r--r-- | test/web/admin_api/admin_api_controller_test.exs | 175 | ||||
-rw-r--r-- | test/web/admin_api/config_test.exs | 95 | ||||
-rw-r--r-- | test/web/rich_media/parser_test.exs | 33 |
17 files changed, 1951 insertions, 78 deletions
diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 5dcc8d059..c05a353d7 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -568,8 +568,9 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret { configs: [ { + "group": string, "key": string, - "value": string or {} or [] + "value": string or {} or [] or {"tuple": []} } ] } @@ -580,6 +581,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret Module name can be passed as string, which starts with `Pleroma`, e.g. `"Pleroma.Upload"`. Atom or boolean value can be passed with `:` in the beginning, e.g. `":true"`, `":upload"`. Integer with `i:`, e.g. `"i:150"`. +Tuple with more than 2 values with `{"tuple": ["first_val", Pleroma.Module, []]}`. +`{"tuple": ["some_string", "Pleroma.Some.Module", []]}` will be converted to `{"some_string", Pleroma.Some.Module, []}`. Compile time settings (need instance reboot): - all settings by this keys: @@ -595,8 +598,9 @@ Compile time settings (need instance reboot): - Method `POST` - Params: - `configs` => [ + - `group` (string) - `key` (string) - - `value` (string, [], {}) + - `value` (string, [], {} or {"tuple": []}) - `delete` = true (optional, if parameter must be deleted) ] @@ -606,6 +610,7 @@ Compile time settings (need instance reboot): { configs: [ { + "group": "pleroma", "key": "Pleroma.Upload", "value": { "uploader": "Pleroma.Uploaders.Local", @@ -619,6 +624,9 @@ Compile time settings (need instance reboot): "follow_redirect": ":true", "pool": ":upload" } + }, + "dispatch": { + "tuple": ["/api/v1/streaming", "Pleroma.Web.MastodonAPI.WebsocketHandler", []] } } } @@ -631,8 +639,9 @@ Compile time settings (need instance reboot): { configs: [ { + "group": string, "key": string, - "value": string or {} or [] + "value": string or {} or [] or {"tuple": []} } ] } diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index cc5425362..4ed2c9789 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -24,7 +24,7 @@ defmodule Mix.Tasks.Pleroma.Config do |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) |> Enum.each(fn {k, v} -> key = to_string(k) |> String.replace("Elixir.", "") - {:ok, _} = Config.update_or_create(%{key: key, value: v}) + {:ok, _} = Config.update_or_create(%{group: "pleroma", key: key, value: v}) Mix.shell().info("#{key} is migrated.") end) @@ -51,7 +51,9 @@ defmodule Mix.Tasks.Pleroma.Config do IO.write( file, - "config :pleroma, #{config.key}#{mark} #{inspect(Config.from_binary(config.value))}\r\n" + "config :#{config.group}, #{config.key}#{mark} #{ + inspect(Config.from_binary(config.value)) + }\r\n" ) {:ok, _} = Repo.delete(config) diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index a8cbfa52a..cf880aa22 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -11,8 +11,17 @@ defmodule Pleroma.Config.TransferTask do def load_and_update_env do if Pleroma.Config.get([:instance, :dynamic_configuration]) and Ecto.Adapters.SQL.table_exists?(Pleroma.Repo, "config") do - Pleroma.Repo.all(Config) - |> Enum.each(&update_env(&1)) + for_restart = + Pleroma.Repo.all(Config) + |> Enum.map(&update_env(&1)) + + # We need to restart applications for loaded settings take effect + for_restart + |> Enum.reject(&(&1 in [:pleroma, :ok])) + |> Enum.each(fn app -> + Application.stop(app) + :ok = Application.start(app) + end) end end @@ -25,11 +34,15 @@ defmodule Pleroma.Config.TransferTask do setting.key end + group = String.to_existing_atom(setting.group) + Application.put_env( - :pleroma, + group, String.to_existing_atom(key), Config.from_binary(setting.value) ) + + group rescue e -> require Logger diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 03dfdca82..953a22ea0 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -377,12 +377,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do if Pleroma.Config.get([:instance, :dynamic_configuration]) do updated = Enum.map(configs, fn - %{"key" => key, "value" => value} -> - {:ok, config} = Config.update_or_create(%{key: key, value: value}) + %{"group" => group, "key" => key, "value" => value} -> + {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value}) config - %{"key" => key, "delete" => "true"} -> - {:ok, _} = Config.delete(key) + %{"group" => group, "key" => key, "delete" => "true"} -> + {:ok, _} = Config.delete(%{group: group, key: key}) nil end) |> Enum.reject(&is_nil(&1)) diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index b7072f050..8b9b658a9 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -12,26 +12,27 @@ defmodule Pleroma.Web.AdminAPI.Config do schema "config" do field(:key, :string) + field(:group, :string) field(:value, :binary) timestamps() end - @spec get_by_key(String.t()) :: Config.t() | nil - def get_by_key(key), do: Repo.get_by(Config, key: key) + @spec get_by_params(map()) :: Config.t() | nil + def get_by_params(params), do: Repo.get_by(Config, params) @spec changeset(Config.t(), map()) :: Changeset.t() def changeset(config, params \\ %{}) do config - |> cast(params, [:key, :value]) - |> validate_required([:key, :value]) - |> unique_constraint(:key) + |> cast(params, [:key, :group, :value]) + |> validate_required([:key, :group, :value]) + |> unique_constraint(:key, name: :config_group_key_index) end @spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def create(%{key: key, value: value}) do + def create(params) do %Config{} - |> changeset(%{key: key, value: transform(value)}) + |> changeset(Map.put(params, :value, transform(params[:value]))) |> Repo.insert() end @@ -43,20 +44,20 @@ defmodule Pleroma.Web.AdminAPI.Config do end @spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def update_or_create(%{key: key} = params) do - with %Config{} = config <- Config.get_by_key(key) do + def update_or_create(params) do + with %Config{} = config <- Config.get_by_params(Map.take(params, [:group, :key])) do Config.update(config, params) else nil -> Config.create(params) end end - @spec delete(String.t()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def delete(key) do - with %Config{} = config <- Config.get_by_key(key) do + @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} + def delete(params) do + with %Config{} = config <- Config.get_by_params(params) do Repo.delete(config) else - nil -> {:error, "Config with key #{key} not found"} + nil -> {:error, "Config with params #{inspect(params)} not found"} end end @@ -77,10 +78,21 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_convert({k, v} = value) when is_tuple(value), do: %{k => do_convert(v)} - defp do_convert(value) when is_binary(value) or is_atom(value) or is_map(value), - do: value + defp do_convert(value) when is_tuple(value), do: %{"tuple" => do_convert(Tuple.to_list(value))} + + defp do_convert(value) when is_binary(value) or is_map(value) or is_number(value), do: value + + defp do_convert(value) when is_atom(value) do + string = to_string(value) + + if String.starts_with?(string, "Elixir."), + do: String.trim_leading(string, "Elixir."), + else: value + end @spec transform(any()) :: binary() + def transform(%{"tuple" => _} = entity), do: :erlang.term_to_binary(do_transform(entity)) + def transform(entity) when is_map(entity) do tuples = for {k, v} <- entity, @@ -101,11 +113,16 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_transform(%Regex{} = value) when is_map(value), do: value + defp do_transform(%{"tuple" => [k, values] = entity}) when length(entity) == 2 do + {do_transform(k), do_transform(values)} + end + + defp do_transform(%{"tuple" => values}) do + Enum.reduce(values, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end) + end + defp do_transform(value) when is_map(value) do - values = - for {key, val} <- value, - into: [], - do: {String.to_atom(key), do_transform(val)} + values = for {key, val} <- value, into: [], do: {String.to_atom(key), do_transform(val)} Enum.sort(values) end @@ -117,28 +134,27 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_transform(entity) when is_list(entity) and length(entity) == 1, do: hd(entity) defp do_transform(value) when is_binary(value) do - value = String.trim(value) + String.trim(value) + |> do_transform_string() + end - case String.length(value) do - 0 -> - nil + defp do_transform(value), do: value - _ -> - cond do - String.starts_with?(value, "Pleroma") -> - String.to_existing_atom("Elixir." <> value) + defp do_transform_string(value) when byte_size(value) == 0, do: nil - String.starts_with?(value, ":") -> - String.replace(value, ":", "") |> String.to_existing_atom() + defp do_transform_string(value) do + cond do + String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix") -> + String.to_existing_atom("Elixir." <> value) - String.starts_with?(value, "i:") -> - String.replace(value, "i:", "") |> String.to_integer() + String.starts_with?(value, ":") -> + String.replace(value, ":", "") |> String.to_existing_atom() - true -> - value - end + String.starts_with?(value, "i:") -> + String.replace(value, "i:", "") |> String.to_integer() + + true -> + value end end - - defp do_transform(value), do: value end diff --git a/lib/pleroma/web/admin_api/views/config_view.ex b/lib/pleroma/web/admin_api/views/config_view.ex index c8560033e..3ccc9ca46 100644 --- a/lib/pleroma/web/admin_api/views/config_view.ex +++ b/lib/pleroma/web/admin_api/views/config_view.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do def render("show.json", %{config: config}) do %{ key: config.key, + group: config.group, value: Pleroma.Web.AdminAPI.Config.from_binary_to_map(config.value) } end diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex index 4a7c5eae0..fb79630e4 100644 --- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex +++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex @@ -1,15 +1,19 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do def parse(html, data, prefix, error_message, key_name, value_name \\ "content") do - with elements = [_ | _] <- get_elements(html, key_name, prefix), - meta_data = - Enum.reduce(elements, data, fn el, acc -> - attributes = normalize_attributes(el, prefix, key_name, value_name) + meta_data = + html + |> get_elements(key_name, prefix) + |> Enum.reduce(data, fn el, acc -> + attributes = normalize_attributes(el, prefix, key_name, value_name) - Map.merge(acc, attributes) - end) do - {:ok, meta_data} + Map.merge(acc, attributes) + end) + |> maybe_put_title(html) + + if Enum.empty?(meta_data) do + {:error, error_message} else - _e -> {:error, error_message} + {:ok, meta_data} end end @@ -27,4 +31,19 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do %{String.to_atom(data[key_name]) => data[value_name]} end + + defp maybe_put_title(%{title: _} = meta, _), do: meta + + defp maybe_put_title(meta, html) when meta != %{} do + case get_page_title(html) do + "" -> meta + title -> Map.put_new(meta, :title, title) + end + end + + defp maybe_put_title(meta, _), do: meta + + defp get_page_title(html) do + Floki.find(html, "title") |> Floki.text() + end end diff --git a/priv/repo/migrations/20190622151019_add_group_key_to_config.exs b/priv/repo/migrations/20190622151019_add_group_key_to_config.exs new file mode 100644 index 000000000..d7a3785d0 --- /dev/null +++ b/priv/repo/migrations/20190622151019_add_group_key_to_config.exs @@ -0,0 +1,12 @@ +defmodule Pleroma.Repo.Migrations.AddGroupKeyToConfig do + use Ecto.Migration + + def change do + alter table("config") do + add(:group, :string) + end + + drop(unique_index("config", :key)) + create(unique_index("config", [:group, :key])) + end +end diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index 9b8a8dd45..c0e433263 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -13,19 +13,37 @@ defmodule Pleroma.Config.TransferTaskTest do test "transfer config values from db to env" do refute Application.get_env(:pleroma, :test_key) - Pleroma.Web.AdminAPI.Config.create(%{key: "test_key", value: [live: 2, com: 3]}) + refute Application.get_env(:idna, :test_key) + + Pleroma.Web.AdminAPI.Config.create(%{ + group: "pleroma", + key: "test_key", + value: [live: 2, com: 3] + }) + + Pleroma.Web.AdminAPI.Config.create(%{ + group: "idna", + key: "test_key", + value: [live: 15, com: 35] + }) Pleroma.Config.TransferTask.start_link() assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3] + assert Application.get_env(:idna, :test_key) == [live: 15, com: 35] on_exit(fn -> Application.delete_env(:pleroma, :test_key) + Application.delete_env(:idna, :test_key) end) end test "non existing atom" do - Pleroma.Web.AdminAPI.Config.create(%{key: "undefined_atom_key", value: [live: 2, com: 3]}) + Pleroma.Web.AdminAPI.Config.create(%{ + group: "pleroma", + key: "undefined_atom_key", + value: [live: 2, com: 3] + }) assert ExUnit.CaptureLog.capture_log(fn -> Pleroma.Config.TransferTask.start_link() diff --git a/test/fixtures/rich_media/non_ogp_embed.html b/test/fixtures/rich_media/non_ogp_embed.html new file mode 100644 index 000000000..62a1d677a --- /dev/null +++ b/test/fixtures/rich_media/non_ogp_embed.html @@ -0,0 +1,1479 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta http-equiv="CACHE-CONTROL" content="NO-CACHE"> + <meta charset="UTF-8"> + <link rel="apple-touch-icon-precomposed" sizes="57x57" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-57x57.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="114x114" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-114x114.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-72x72.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-144x144.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="60x60" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-60x60.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="120x120" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-120x120.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="76x76" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-76x76.png?nc=1" /> +<link rel="apple-touch-icon-precomposed" sizes="152x152" href="https://img.mfcimg.com/images/favicons/apple-touch-icon-152x152.png?nc=1" /> +<link rel="icon" type="image/png" href="https://img.mfcimg.com/images/favicons/favicon-196x196.png?nc=1" sizes="196x196" /> +<link rel="icon" type="image/png" href="https://img.mfcimg.com/images/favicons/favicon-96x96.png?nc=1" sizes="96x96" /> +<link rel="icon" type="image/png" href="https://img.mfcimg.com/images/favicons/favicon-32x32.png?nc=1" sizes="32x32" /> +<link rel="icon" type="image/png" href="https://img.mfcimg.com/images/favicons/favicon-16x16.png?nc=1" sizes="16x16" /> +<link rel="icon" type="image/png" href="https://img.mfcimg.com/images/favicons/favicon-128.png?nc=1" sizes="128x128" /> +<meta name="application-name" content="MyFreeCams.com Profiles" /> +<meta name="msapplication-TileColor" content="#008000" /> +<meta name="msapplication-TileImage" content="https://img.mfcimg.com/images/favicons/mstile-144x144.png?nc=1" /> +<meta name="msapplication-square70x70logo" content="https://img.mfcimg.com/images/favicons/mstile-70x70.png?nc=1" /> +<meta name="msapplication-square150x150logo" content="https://img.mfcimg.com/images/favicons/mstile-150x150.png?nc=1" /> +<meta name="msapplication-wide310x150logo" content="https://img.mfcimg.com/images/favicons/mstile-310x150.png?nc=1" /> +<meta name="msapplication-square310x310logo" content="https://img.mfcimg.com/images/favicons/mstile-310x310.png?nc=1" /> + + <script src="https://img.mfcimg.com/profiles/jquery/jquery-1.9.1.min.js"></script> +<script src="https://img.mfcimg.com/profiles/jquery/jquery-ui-1.9.2.min.js"></script> +<script src="https://img.mfcimg.com/profiles/jquery/jquery.ui.touch-punch.min.js"></script> <script> + var g_hPlatform = { "id": 1, "domain": "myfreecams.com", "name": "MyFreeCams", "code": "mfc", "image_url": "https://img.mfcimg.com/" }; + + try { document.domain = 'myfreecams.com'; } catch (e) {} + + var MfcAssets = { + images: "/bundles/mfcprofile/vendor/img/", + urls: { + www: "https://www.myfreecams.com/", + new_comments: "/BlueAngelLove/comments/since/0" + } + }; + + var MfcPageVars = { + userId: 0, + accessLevel: 0, + token: "xIqyjzUBSrt6Rbl_su7UOrDxNZJlZNc4nsWh6eXxDkg", + profileState: {"number":127,"string":"Offline"}, + serverTime: {"unixTime":1561209909,"time":"6:25am PDT","dst":1}, + profileUsername: "BlueAngelLove", + admirers: 4719, + username: "", + userPhotoUrl: "", + vToken: "4c4ea23b221f89b73c964b7f99a50f78", + avatarRev: 0, + avgRating: {"rating_count":7060,"rating_average":"4.8681"}, + rating: 0 +}; + + + function MfcProfilePage( jQuery ) + { + var _self = this; + + _self.$ = jQuery; + + _self.token = ( typeof(MfcPageVars) !== 'undefined' && MfcPageVars.token ) ? MfcPageVars.token : _self.$('meta[name=token]').attr('content'); + + _self.beforeDomReady(); + + + _self.$(function(){ _self.afterDomReady(); }); + }; + + MfcProfilePage.prototype.beforeDomReady = function() + { + var _self = this; + var $ = _self.$; + + if ( _self.token ) + { + $.ajaxSetup({ + beforeSend: function(xhr, settings) { + if ( settings.type === 'GET' || settings.crossDomain ) + return; + + if ( $.type(settings.data) === 'object' && $.type(settings.data.append) === 'function' ) + { + settings.data.append('_token', _self.token); + } + else if ( $.type(settings.data) === 'string' && settings.data.indexOf('_token=') === -1 ) + { + if ( settings.data.length === 0 ) + { + xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); + } else { + settings.data += '&'; + } + + settings.data += encodeURIComponent('_token') + '=' + encodeURIComponent(_self.token); + } + } + }); + + $(document).on('submit', 'form', function(e) + { + if ( ! $(this).find('#_token').length && ! $(this).data('mfc-no-token') ) + $(this).append($('<input type="hidden" name="_token" id="_token" value="' + _self.token + '">')); + }); + } + }; + + MfcProfilePage.prototype.afterDomReady = function() + { + var _self = this; + var $ = this.$; + + var page = $('body').data('mfc-page'); + + if ( $.isFunction(_self[page]) ) + _self[page](); + }; + + new MfcProfilePage(jQuery); +</script> + + <link href="https://img.mfcimg.com/profiles/prod/22793316144741120/css/profiles.css?nc=22793316144741120" type="text/css" rel="stylesheet"> + + <title>BlueAngelLove's Homepage on MyFreeCams.com</title> + <meta name="description" content="BlueAngelLove's webcam homepage on MyFreeCams.com - your #1 adult webcam community"> + <meta name="keywords" content="webcams,models,adult,community,nude,chat,video"> + + <style type="text/css"> + body.mfc_display_inline_mode #header_bar, body.mfc_display_inline_mode #footer_bar { + visibility: hidden; + } + body.mfc_profile_standard.mfc_display_inline_mode { + margin-left: 0; + margin-right: 0; + padding-left: 5px; + padding-right: 5px; + } + body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me { + display: flex; + flex-flow: wrap; + } + body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me .heading { + flex: 0 0 100%; + } + body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me .container { + flex: 0 1 50%; + margin: 0; + padding: 0; + } + body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me #about_me_container, body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me #tags_container { + flex: 0 0 100%; + margin-top: 0; + margin-bottom: 0; + } + @media (max-width: 850px) { + body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me .container { + flex: 0 0 100%; + } + } + @media (min-width: 1500px) { + body.mfc_profile_standard.mfc_display_inline_mode #profile_about_me .container { + flex: 0 0 33%; + } + } + </style> + + <link href="/BlueAngelLove/css?nc=204272526" rel="stylesheet" type="text/css"> + + + <script type="text/javascript"> + g_bInIframe = (function(w) { + try { + return w.self !== w.top; + } catch (e) { + return true; + } + return false; + })(window); + + (function(w,d) { + 'use strict'; + + var hrefClickFn = function (e) { + e = e || w.event; + + var target = findHrefElFn(e.target || e.srcElement); + + if ( target != undefined && ((target.hostname + target.pathname.replace(/(^\/?)/,'/')).toLowerCase() !== (location.hostname + location.pathname).toLowerCase()) ) { + target.setAttribute('target', '_blank'); + target.setAttribute('rel', 'noopener noreferrer'); + } + + return true; + }; + + var isHrefElFn = function(el) { + var elName = (el.nodeName || el.tagName).toLowerCase(); + if ( (elName === 'a' || elName === 'area') && el.href != undefined ) { return true; } + return false; + }; + + var findHrefElFn = function(el) { + if ( isHrefElFn(el) ) { return el; } + while (el = el.parentNode) { + if ( isHrefElFn(el) ) { return el; } + } + return undefined; + }; + + if ( g_bInIframe ) { + if ( d.addEventListener ) { + d.addEventListener('click', hrefClickFn); + } else { + d.attachEvent('onclick', hrefClickFn); + } + } + })(window, document); +</script> + + </head> + <body class="mfc_profile_customized" data-mfc-page="userShow"> + <script type="text/javascript"> + (function(w,d,v) { + 'use strict'; + + var classes = []; + var search = w.location.search || ''; + var vs = (typeof v === 'object' && v.profileState) ? v.profileState.number : 127; + + if ( search.match(/[?&]inline_mode=1/) ) { + classes.push('mfc_display_inline_mode'); + } + if ( search.match(/[?&]online=1/) || vs != 127 ) { + classes.push('mfc_online'); + } + if ( 'Model' === 'Model' && ( search.match(/[?&]broadcasting=1/) || vs < 90 ) ) { + classes.push('mfc_broadcasting'); + } + + if ( classes.length ) { + d.getElementsByTagName('body')[0].className += ' ' + classes.join(' '); + } + + })(window, document, MfcPageVars); +</script> + <div id="fixed_background"></div> + + <div id="header_bar"> + <div class="header_links"> + <a href="/">Profiles.MyFreeCams.com</a> | + <a href='https://www.myfreecams.com/'>MyFreeCams.com</a> | + <a href="/_/my_profile">My Profile</a> | + <a href="/_/login">Profile Settings</a> + </div> + + <div class="clearfix header_time"> + + <div id="server_time"> + <table> + <tbody> + <tr> + <td>Your Time:</td> + <td id="your_time"></td> + </tr> + <tr> + <td>MyFreeCams Time:</td> + <td id="mfc_time"></td> + </tr> + </tbody> + </table> + </div> + + </div> + </div> + + <div id="profile"> + <div class="profile_row"> + <div class="profile_section" id="profile_header"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + <div id="avatar_holder"> + <img id="profile_avatar" class="img_radius_shadow" src="https://img.mfcimg.com/photos2/320/3204009/avatar.90x90.jpg?nc=1557647675" onError="this.onerror=null; this.src='https://img.mfcimg.com/images/nophoto-f.gif';"> + </div> + + <div id="profile_header_container"> + <div class="heading"> + BlueAngelLove + </div> + + <div class="container" id="status_container"> + <div class="label" id="status_label"> + Status: + </div> + <div class="value" id="status_value"> + <span id="member_status_value" class="hidden"></span> + <span id="member_type_value"> - Model -</span> + <span id="member_message_value" class="hidden" data-mfc-member-type="Model"><a href="#" id="show_message_dialog">Send a MyFreeCams Mail</a></span> + </div> + </div> + + + + <div class="container" id="blurb_container"> + <span class="label" id="blurb_label"> + Profile Headline: + </span> + + <span class="value" id="blurb_value"> + Enjoy and Love + </span> + </div> + + + + + + + + + <div class="container" id="unix_last_broadcast_container"> + <span class="label" id="unix_last_broadcast_label"> + Last Broadcast: + </span> + + <span class="value convert-time" id="unix_last_broadcast_value" data-mfc-unix-time="1561100400" data-mfc-time-format="ddd, MMM D YYYY"></span> + </div> + + + + + + <div class="container" id="unix_last_updated_container"> + <span class="label" id="unix_last_updated_label"> + Last Updated: + </span> + + <span class="value convert-time" id="unix_last_updated_value" data-mfc-unix-time="1561193088" data-mfc-time-format="llll"></span> + </div> + + + + </div> + </div> + </div> + </div> + + <div class="profile_row" id="profile_main_about_holder"> + + <div id="profile_main_photo"> + <div class="profile_section"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + + <div class="heading"> + My Most Recent Pictures + </div> + <div class="recent_photos"> + <img src="https://img.mfcimg.com/photos2/320/3204009/986-665-202-679-12065535.80x80.jpg" class="img_radius_shadow show_preview" onError="this.onerror=null; this.src='https://img.mfcimg.com/images/nophoto-f.gif';" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/986-665-202-679-12065535.250.jpg"> + </div> + </div> + </div> + </div> + + <div class="profile_section" id="profile_about_me_friends"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + <div class="profile_subsection" id="profile_about_me"> + + <div class="heading"> + About Me + </div> + + + + <div class="container" id="username_container"> + <span class="label" id="username_label"> + Username: + </span> + + <span class="value" id="username_value"> + BlueAngelLove </span> + </div> + + + + + + + + + <div class="container" id="gender_container"> + <span class="label" id="gender_label"> + Gender: + </span> + + <span class="value" id="gender_value"> + Female </span> + </div> + + + + + + <div class="container" id="body_type_container"> + <span class="label" id="body_type_label"> + Body Type: + </span> + + <span class="value" id="body_type_value"> + Athletic </span> + </div> + + + + + + <div class="container" id="ethnicity_container"> + <span class="label" id="ethnicity_label"> + Ethnicity: + </span> + + <span class="value" id="ethnicity_value"> + Other </span> + </div> + + + + + + <div class="container" id="hair_container"> + <span class="label" id="hair_label"> + Hair: + </span> + + <span class="value" id="hair_value"> + Brown </span> + </div> + + + + + + <div class="container" id="eyes_container"> + <span class="label" id="eyes_label"> + Eyes: + </span> + + <span class="value" id="eyes_value"> + Blue </span> + </div> + + + + + + <div class="container" id="weight_container"> + <span class="label" id="weight_label"> + Weight: + </span> + + <span class="value" id="weight_value"> + 45 kilos </span> + </div> + + + + + + <div class="container" id="height_container"> + <span class="label" id="height_label"> + Height: + </span> + + <span class="value" id="height_value"> + 165 centimeters </span> + </div> + + + + + + <div class="container" id="age_container"> + <span class="label" id="age_label"> + Age: + </span> + + <span class="value" id="age_value"> + 34 </span> + </div> + + + + + + <div class="container" id="city_container"> + <span class="label" id="city_label"> + City: + </span> + + <span class="value" id="city_value"> + Mountains </span> + </div> + + + + + + + + + + + + <div class="container" id="sexual_preference_container"> + <span class="label" id="sexual_preference_label"> + Sexual Preference: + </span> + + <span class="value" id="sexual_preference_value"> + Bisexual </span> + </div> + + + + + + <div class="container" id="smoke_container"> + <span class="label" id="smoke_label"> + Smoke: + </span> + + <span class="value" id="smoke_value"> + Non Smoker </span> + </div> + + + + + + <div class="container" id="drink_container"> + <span class="label" id="drink_label"> + Drink: + </span> + + <span class="value" id="drink_value"> + Non Drinker </span> + </div> + + + + + + <div class="container" id="drugs_container"> + <span class="label" id="drugs_label"> + Drugs: + </span> + + <span class="value" id="drugs_value"> + Never </span> + </div> + + + + + + + + + <div class="container" id="occupation_container"> + <span class="label" id="occupation_label"> + Occupation/Major: + </span> + + <span class="value" id="occupation_value"> + Guide </span> + </div> + + + + + + + + + <div class="container" id="favorite_food_container"> + <span class="label" id="favorite_food_label"> + Favorite Food: + </span> + + <span class="value" id="favorite_food_value"> + Chocolate </span> + </div> + + + + + + <div class="container" id="pets_container"> + <span class="label" id="pets_label"> + Pets: + </span> + + <span class="value" id="pets_value"> + I dont like pets </span> + </div> + + + + + + <div class="container" id="automobile_container"> + <span class="label" id="automobile_label"> + Automobile: + </span> + + <span class="value" id="automobile_value"> + Ford </span> + </div> + + + + + + <div class="container" id="about_me_container"> + <span class="label" id="about_me_label"> + About Me: + </span> + + <span class="value" id="about_me_value"> + <a href="//www.dmca.com/Protection/Status.aspx?ID=96b05ddf-1265-4f81-9d84-7dcfeb87cbb6" title="DMCA.com Protection Status" class="dmca-badge"> <img src="https://images.dmca.com/Badges/dmca_protected_16_120.png?ID=96b05ddf-1265-4f81-9d84-7dcfeb87cbb6" alt="DMCA.com Protection Status"></a><a href="http://www.cutercounter.com/" target="_blank" rel="noopener noreferrer"><img src="http://www.cutercounter.com/hits.php?id=grmpackf&nd=7&style=102" border="0" alt="website counter"></a> +<div id="myCv" class="gen"> +<div class="defaultbg"></div> +<div class="maintitle">BlueAngelLove</div> + <div id="buttons"> + <a href="https://wa.me/40747018024" class="btn blue"> CONTACT ME </a> + <div class="corp"> + + <div id="ModelCard"> + <img src="https://img.mfcimg.com/photos2/320/3204009/314-736-287-236-10552594.jpg" alt="Model's image"><hr><div class="bum"></div> + <div class="bum"><a href="http://www.myfreecams.com/mfc2/php/tip.php?request=tip&username=blueangellove" title="Tip Me Offline">Tip Me Offline</a></div> + <div class="bum"><a href="http://www.amazon.co.uk/wishlist/3D0MOTP0S0SE5" target="_blank" title="My Amazon Wishlist" rel="noopener noreferrer">My Amazon Wishlist</a></div> + <div class="bum"><a href="https://twitter.com/BlueAngelLove33" target="_blank" title="Follow me on Twitter" rel="noopener noreferrer">Follow Me on Twitter</a></div> + <div class="bum"><a href="https://wa.me/40747018024" target="_blank" title="Follow me on WhatsApp" rel="noopener noreferrer">Follow Me on Whatsapp</a></div> + <div class="bum"><a href="https://www.instagram.com/blueangellove3?r=nametag" title="Follow me on Instagram">Follow Me on Instagram</a></div> + <div class="bum"><a href="https://www.snapchat.com/add/cjullyana" title="Follow me on Snapchat">Follow Me on SnapChat</a></div> + <div class="bum"><a href="http://hatscripts.com/addskype?BlueAngelLove33" title="Follow me on Skype">Follow Me on Skype</a></div> + <div class="bum"><a href="https://www.youtube.com/playlist?list=PLGqo-7BiklVM37HIBud981EpiXxV3yM4m" title="Follow me on Youtube">Follow Me on Youtube </a></div> + <div class="bum"><a href="#roomrules" target="_blank" title="Join my Chat Room" rel="noopener noreferrer">Join My Room</a></div> + <div class="bum"><a href="https://MFCsha.re/BlueAngelLove" title="Follow me on MFC Share">Follow Me on MFC Share</a></div> + <div class="bum"><a href="https://social.myfreecams.com/BlueAngelLove" title="Follow me on Social MFC">Follow Me on Social MFC </a></div> + <div class="bum"><a href="https://www.rabb.it/s/d556sr" title="Follow me on Rabbit TV">Follow me on Rabbit TV</a></div> + <div class="bum"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y8KLFSLZJAKP2&source=url" title="Spoil Me and Offer Your Gift">Spoil Me and Offer Your Gift</a></div> + <div class="bum"><a href="https://player.vimeo.com/video/326274838" title="Follow Me">Follow Me</a></div> + <div class="bum"><a href="https://www.timeanddate.com/worldclock/personal.html?cities=179,136,248,250,263,152,2462,716,195,69&wch=2" title="TIME CONVERTOR">TIME CONVERTOR</a></div> + <hr></div> + </div> + <div id="AboutMe"> + <div class="skilltitle">Angel</div> + <div class="corp corpus xcr"> + <div class="unscor"> + I Want To Be Seduced + <div class="skills_model1"><div class="metru_experience skill bxhdw"></div></div> + </div> + <div class="unscor"> + I Love Flirt + <div class="skills_model1"><div class="metru_coding skill bxhdw"></div></div> + </div> + <div class="unscor"> + I Want Be Part Of Your life + <div class="skills_model1"><div class="metru_concept skill bxhdw"></div></div> + </div> + <div class="unscor"> + I Love Dancing + <div class="skills_model1"><div class="metru_concept skill bxhdw"></div></div> + </div> + <div class="unscor"> + I Love Erotic Chats + <div class="skills_model1"><div class="metru_graphic skill bxhdw"></div></div> + </div> + <div class="unscor"> + I am Funny + <div class="skills_model1"><div class="metru_coding skill bxhdw"></div></div> + </div> + <div class="unscor"> + I Enjoy C2C + <div class="skills_model1"><div class="metru_experience skill bxhdw"></div></div> + </div> + <div class="unscor"> + I Love Sex and Feel u + <div class="skills_model1"><div class="metru_concept skill bxhdw"></div></div> + </div> + </div> + <hr></div> + </div> + <hr><div class="maintitle">June Month Contestst-Top 3 tippers Get A gift mailed,videos,pictures and will my right hand full month and room helpers as well (be my men for a month or who knows...maybe forever) *** +Love Ya Angels*** We are currently ranked #2200 overall </div> + <p class="dasinfo">Get Listed on My Wall of Fame</p> + <div class="corp zreq"> + <div class="ttippers xcr"> + + <p> ElmosEgo 6570 Tks </p> + <p> Rw2lite 4800 Tks </p> + <p> Toastboi 2093 Tks </p> + <p> Acoolahole 1850 Tks </p> + <p> Gonodog 1299 Tks </p> + <p> Pumpy_G 800 Tks </p> + <p> Fowser 690 Tks </p> + <p> Aquanautic 600 Tks </p> + <p> Daveonthelake 535 Tks </p> + <p> Wildpervert2 500 Tks </p> + <p> Cloud10101 350 Tks </p> + <p> Branson102 337 Tks </p> + <p> TheCopperhead 329 Tks </p> + <p> Mouche99 250 Tks </p> + <p> The88drummer 233 Tks </p> + <p> Stringtrees86 199 Tks </p> + <p> Blazegordon 183 Tks </p> + <p> Waiting_4 183 Tks </p> + <p> Sam_mie 170 Tks </p> + <p> UtterTripe 150 Tks </p> + <p> Darth_penguin 150 Tks </p> + <p> Playfullpurv 120 Tks </p> + <p> Jordnsprings 103 Tks </p> + <p> Travelinlover 100 Tks </p> + <p> Da884 100 Tks </p> + + </div> + <a href="https://imgbb.com/"><img src="https://i.ibb.co/mybZhYn/cory1.jpg" alt="cory1" border="0"></a> +</div> + <hr><div class="maintitle">May Contest winners - Each month Top 3 tippers Get A gift mailed, videos and pictures - Love Ya Angels </div> + <p class="dasinfo">Get Listed on My Wall of Fame</p> + <div class="corp zreq"> + <div class="ttippers xcr"> + <p> Rw2lite </p> + <p> ElmosEgo </p> + <p> TJuonesWoah </p> + +</div> + <a href="https://imgbb.com/"><img src="https://i.ibb.co/mybZhYn/cory1.jpg" alt="cory1" border="0"></a> +</div> + <hr><div class="maintitle"> Menu Per Day </div> + <p class="dasinfo">LOVE YA ANGELS</p> + <div class="corp zreq"> + <div class="ttippers xcr"> + <p> Monday - Outfits Strip </p> + <p> Tusday - Raffle </p> + <p> Wensday - Gamblers Night </p> + <p> Thusday - Orgasmic Vibra or Dildos </p> + <p> Friday - Wheel/Treat or Trick </p> + <p> Saturday - Phrase </p> + <p> Sunday - Keno and Boyfriend choice </p> + + + + </div> + <div class="dasinfo">You have to tip to get listed above so do your best to get on my exclusive Top Tippers List</div> + <div class="bum"></div> + </div> + <a href="https://ibb.co/vcFmK7x"><img src="https://i.ibb.co/j8NG1cv/Whats-App-Image-2019-01-09-at-10-35-17.jpg" alt="Whats-App-Image-2019-01-09-at-10-35-17" border="0"></a> + <a href="https://ibb.co/RcMF0T5"><img src="https://i.ibb.co/kXr782d/45280406-1564895203655742-4887638015087738880-n.jpg" alt="45280406-1564895203655742-4887638015087738880-n" border="0"></a> + <a href="https://ibb.co/1s0Tp2r"><img src="https://i.ibb.co/gvrJXgS/best.jpg" alt="best" border="0"></a> + <a href="https://ibb.co/cJmJHHv"><img src="https://i.ibb.co/F6P6MMW/Whats-App-Image-2019-01-09-at-10-35-16.jpg" alt="Whats-App-Image-2019-01-09-at-10-35-16" border="0"></a> + + <div class="bum"><a href="http://www.myfreecams.com/mfc2/php/tip.php?request=tip&username=blueangellove" title="Tip Me Offline">Tip Me Offline</a></div> + <div class="bum"><a href="http://www.amazon.co.uk/wishlist/3D0MOTP0S0SE5" target="_blank" title="My Amazon Wishlist" rel="noopener noreferrer">My Amazon Wishlist</a></div> + <div class="bum"><a href="https://twitter.com/BlueAngelLove33" target="_blank" title="Follow me on Twitter" rel="noopener noreferrer">Follow Me on Twitter</a></div> + <div class="bum"><a href="https://wa.me/40747018024" target="_blank" title="Follow me on WhatsApp" rel="noopener noreferrer">Follow Me on Whatsapp</a></div> + <div class="bum"><a href="https://www.instagram.com/blueangellove3?r=nametag" title="Follow me on Instagram">Follow Me on Instagram</a></div> + <div class="bum"><a href="https://www.snapchat.com/add/cjullyana" title="Follow me on Snapchat">Follow Me on SnapChat</a></div> + <div class="bum"><a href="http://hatscripts.com/addskype?BlueAngelLove33" title="Follow me on Skype">Follow Me on Skype</a></div> + <div class="bum"><a href="https://www.youtube.com/playlist?list=PLGqo-7BiklVM37HIBud981EpiXxV3yM4m" title="Follow me on Youtube">Follow Me on Youtube </a></div> + <div class="bum"><a href="#roomrules" target="_blank" title="Join my Chat Room" rel="noopener noreferrer">Join My Room</a></div> + <div class="bum"><a href="https://MFCsha.re/BlueAngelLove" title="Follow me on MFC Share">Follow Me on MFC Share</a></div> + <div class="bum"><a href="https://social.myfreecams.com/BlueAngelLove" title="Follow me on Social MFC">Follow Me on Social MFC </a></div> + <div class="bum"><a href="https://www.rabb.it/s/d556sr" title="Follow me on Rabbit TV">Follow me on Rabbit TV</a></div> + <div class="bum"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y8KLFSLZJAKP2&source=url" title="Spoil Me and Offer Your Gift">Spoil Me and Offer Your Gift</a></div> + <div class="bum"><a href="https://player.vimeo.com/video/326274838" title="Follow Me">Follow Me</a></div> + <div class="bum"><a href="https://www.timeanddate.com/worldclock/personal.html?cities=179,136,248,250,263,152,2462,716,195,69&wch=2" title="TIME CONVERTOR">TIME CONVERTOR</a></div> + <hr><div id="GNav"> + <div id="GNwrapper"> + <a class="abMe" title="About Me" href="#aboutmesection"></a></div> +</div> +<div class="bum"><a href="https://MFCsha.re/BlueAngelLove" title="Follow me on MFC Share">Follow Me on MFC Share</a></div> +<img src="https://i.ibb.co/Pmt2PsP/Whats-App-Image-2019-05-12-at-05-55-35-1.jpg" alt="Whats-App-Image-2019-05-12-at-05-55-35-1" border="0"><img src="https://image.ibb.co/bt1tzq/lovense-level.png" alt="lovense-level" border="0"><div> +<span class="neontexte"></span></div> +<div id="OneSection"> +<div></div> +<div> +<img src="http://1.bp.blogspot.com/-qTHLNVFggQU/VFdFIOFPDqI/AAAAAAAAGdU/6cWnDLVp0d8/s1600/findme.png" class="findme" alt="camgirl xxx amateur sex sexy"></div> +</div> +<div> +<div id="TwoSection"> +<div id="aboutmesection"> +<a href="https://ibb.co/ZS2D4vh"><img src="https://i.ibb.co/421rvCj/39741863-284302529029606-7659956026455621632-n.jpg" alt="39741863-284302529029606-7659956026455621632-n" border="0"></a> +<div id="abtmesec" class="frame"> +<span class="neontext">Let's Fun Laugh Live</span><br><i>I am Jullia from Transylvania and is a pleasure to have u around Enjoy me and my room</i><br><br><span class="neontext">BlueAngelLove</span><br><i>I am good, but not an angel. I do sin, but I am not the devil. I am just a girl in a big world trying to find someone to love and be loved</i><br><br></div> +<a href="https://ibb.co/gvVKkkf"><img src="https://i.ibb.co/6vBCjjT/20171114-113848.jpg" alt="20171114-113848" border="0"></a><a> +</a></div>~~~Live~Laugh~Love~~~<i><a href="https://info.flagcounter.com/1Ea8"><img src="https://s04.flagcounter.com/countxl/1Ea8/bg_85C2FF/txt_242424/border_CCCCCC/columns_3/maxflags_33/viewers_0/labels_1/pageviews_0/flags_0/percent_0/" alt="Flag Counter" border="0"></a> +</i></div><div id="vimlft" class="frame"></div></div></div> </span> + </div> + + + + + + <div class="container" id="tags_container"> + <span class="label" id="tags_label"> + Tags: + </span> + + <span class="value" id="tags_value"> + natural, blue eyes, toys, funny, oil, shower, fetish, costume, sex, natural, masturbation, finger, dp, anal, girl next door, romantic, naughty, pervert, open mind, play roles, horny, playful, smiley, lover, sweet, sexy, beautiful, hot, shaved, friendly, pussy, skype </span> + </div> + + + + </div> + + <div class="profile_subsection" id="profile_friends"> + + <div class="heading"> + Friends + </div> + + <div class="container" id="average_rating_container"> + <span class="label" id="average_rating_label"> + Average Rating: + </span> + <span class="value" id="average_rating_value"> + <span id="average_rating"></span> + <span id="average_rating_count"></span> + </span> + </div> + + <div class="container" id="rate_container"> + <span class="label" id="rate_label"> + Rate BlueAngelLove: + </span> + <span class="value" id="rate_value"> + <form id="new_rating" class="hidden" action="/BlueAngelLove/ratings" method="post"> + <span id="rating_value_bar"></span> + <span id="rating_confirm" class="hidden emphasis notice"></span> +</form> +<div id="new_rating_login_message" class="hidden"> + You must <a href="/_/login">login</a> to rate. +</div> </span> + </div> + + <div class="container" id="admirers_container"> + <span class="label" id="admirers_label"> + Admirers: + <br> + <form id="new_admirer" action="/BlueAngelLove/admirers" method="post"> + + (<a href='#' id="admire">admire</a><span id="admire_confirm" class="hidden notice">admired!</span>) +</form> </span> + <span class="value" id="admirers_value"></span> + </div> + + <div class="container" id="friends_container"> + <span class="label" id="friends_label"> + Profile Friends: + <br> + <form id="new_homepage_friend" action="/BlueAngelLove/homepage_friends" method="post"> + + (<a href='#' id='make_friend'>make friend</a><span id="make_friend_confirm" class="hidden notice">added!</span>) +</form> </span> + <span class="value" id="friends_value"> + <a href="/Schnitzngrubn">Schnitzngrubn</a> + <a href="/UtterTripe">UtterTripe</a> + <a href="/MisterPopular">MisterPopular</a> + <a href="/neoviewer">neoviewer</a> + <a href="/lasse1991">lasse1991</a> + <a href="/toastboi">toastboi</a> + <a href="/obiwan1965">obiwan1965</a> + <a href="/Eastie_Beasty">Eastie_Beasty</a> + <a href="/Robby1890">Robby1890</a> + <a href="/rw2lite">rw2lite</a> + <a href="/zoomie2178">zoomie2178</a> + <a href="/AS_rayman41">AS_rayman41</a> + <a href="/CJamz87">CJamz87</a> + <a href="/Dunky4Jullia">Dunky4Jullia</a> + <a href="/Zdasher">Zdasher</a> + <a href="/Fowser">Fowser</a> + <a href="/buffaloman69">buffaloman69</a> + <a href="/Numb33rs">Numb33rs</a> + <a href="/ElmosEgo">ElmosEgo</a> + <a href="/DaleCooper_">DaleCooper_</a> + <a href="/Aquanautic">Aquanautic</a> + <a href="/Waiting_4">Waiting_4</a> + <a href="/Oliver_xXx">Oliver_xXx</a> + <a href="/motion454">motion454</a> + <a href="/The_Greg1">The_Greg1</a> + <a href="/Razumichin">Razumichin</a> + <a href="/Sam_mie">Sam_mie</a> + </span> + </div> + + <div class="container" id="favorite_models_container"> + <span class="label" id="favorite_models_label"> + Favorite Models: + </span> + <span class="value" id="favorite_models_value"> + <a href="/BlueAngelLove">BlueAngelLove</a> + </span> + </div> + </div> + </div> + </div> + + </div> + <div class="profile_row"> + <div class="profile_section" id="profile_password_photo_galleries"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + <div class="heading"> + Password Protected Galleries + </div> + + <div class="holder" id="password_photo_gallery_control"></div> + <ul class="photo_gallery_previews" id="password_photo_gallery_previews"> + <li class="photo_gallery_preview" data-mfc-name="Paris , Disneyland , Belgium , Frankfurt , Berlin" data-mfc-url="/BlueAngelLove/view_gallery/498241/password"> + <div class="photo_gallery_name"> + <a href="#" class="photo_gallery_link" data-mfc-gallery="498241" data-mfc-protected="1">Paris , Disneyland , Belgium , Frankfurt , Berlin</a> + + </div> + <a href="#" class="photo_gallery_link" data-mfc-gallery="498241" data-mfc-protected="1"><img class='photo_gallery_lock img_radius_shadow' src='https://img.mfcimg.com/images/lock-icon.gif'></a> + + <div class="photo_gallery_count"> + 17 Photos + </div> + </li> + + + <li class="photo_gallery_preview" data-mfc-name="Paris , Disneyland , Belgium , Frankfurt , Berlin ..." data-mfc-url="/BlueAngelLove/view_gallery/498240/password"> + <div class="photo_gallery_name"> + <a href="#" class="photo_gallery_link" data-mfc-gallery="498240" data-mfc-protected="1">Paris , Disneyland , Belgium , Frankfurt , Berlin ...</a> + + </div> + <a href="#" class="photo_gallery_link" data-mfc-gallery="498240" data-mfc-protected="1"><img class='photo_gallery_lock img_radius_shadow' src='https://img.mfcimg.com/images/lock-icon.gif'></a> + + <div class="photo_gallery_count"> + 37 Photos + </div> + </li> + + + <li class="photo_gallery_preview" data-mfc-name="CJ Art - Free Gallery - Just pm me and i give u the password" data-mfc-url="/BlueAngelLove/view_gallery/343862/password"> + <div class="photo_gallery_name"> + <a href="#" class="photo_gallery_link" data-mfc-gallery="343862" data-mfc-protected="1">CJ Art - Free Gallery - Just pm me and i give u the password</a> + + </div> + <a href="#" class="photo_gallery_link" data-mfc-gallery="343862" data-mfc-protected="1"><img class='photo_gallery_lock img_radius_shadow' src='https://img.mfcimg.com/images/lock-icon.gif'></a> + + <div class="photo_gallery_count"> + 15 Photos + </div> + </li> + + + <li class="photo_gallery_preview" data-mfc-name="4MyAngels - Free Gallery - Just pm me and i give u the password" data-mfc-url="/BlueAngelLove/view_gallery/340500/password"> + <div class="photo_gallery_name"> + <a href="#" class="photo_gallery_link" data-mfc-gallery="340500" data-mfc-protected="1">4MyAngels - Free Gallery - Just pm me and i give u the password</a> + + </div> + <a href="#" class="photo_gallery_link" data-mfc-gallery="340500" data-mfc-protected="1"><img class='photo_gallery_lock img_radius_shadow' src='https://img.mfcimg.com/images/lock-icon.gif'></a> + + <div class="photo_gallery_count"> + 97 Photos + </div> + </li> + + + </ul> + </div> + </div> + + </div> + <div class="hidden profile_row" id="password_photo_galleries"> + <div class="profile_section"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + </div> + </div> + </div> + <div class="profile_row"> + <div class="profile_section" id="profile_photo_galleries"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + <div class="heading"> + Photo Galleries + </div> + + <div class="holder" id="photo_gallery_control"></div> + <ul class="photo_gallery_previews" id="photo_gallery_previews"> + <li class="photo_gallery_preview" data-mfc-name="Recent Photo" > + <div class="photo_gallery_name"> + <a href="#" class="photo_gallery_link" data-mfc-gallery="3" >Recent Photo</a> + + </div> + <a href="#" class="photo_gallery_link" data-mfc-gallery="3" ><img class='photo_gallery_image img_radius_shadow' src='https://img.mfcimg.com/photos2/320/3204009/986-665-202-679-12065535.80x80.jpg' onError="this.onerror=null; this.src='https://img.mfcimg.com/images/nophoto-f.gif';"></a> + + <div class="photo_gallery_count"> + 1 Photo + </div> + </li> + + + <li class="photo_gallery_preview" data-mfc-name="jullia" > + <div class="photo_gallery_name"> + <a href="#" class="photo_gallery_link" data-mfc-gallery="56075" >jullia</a> + + </div> + <a href="#" class="photo_gallery_link" data-mfc-gallery="56075" ><img class='photo_gallery_image img_radius_shadow' src='https://img.mfcimg.com/photos2/320/3204009/681-423-335-230-1243247.80x80.jpg' onError="this.onerror=null; this.src='https://img.mfcimg.com/images/nophoto-f.gif';"></a> + + <div class="photo_gallery_count"> + 68 Photos + </div> + </li> + + + </ul> + </div> + </div> + + </div> + <div class="hidden profile_row" id="photo_galleries"> + <div class="profile_section"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + <div class="hidden photo_gallery" id="profile_photo_gallery_3"> + <div class="heading"> + Recent Photo + </div> + + <div class="images"> + <a href="https://img.mfcimg.com/photos2/320/3204009/986-665-202-679-12065535.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/986-665-202-679-12065535.80x80.jpg" data-mfc-caption="" data-mfc-width="1600" data-mfc-height="1200" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/986-665-202-679-12065535.250.jpg"></a> + </div> +</div> <div class="hidden photo_gallery" id="profile_photo_gallery_56075"> + <div class="heading"> + jullia + </div> + + <div class="images"> + <a href="https://img.mfcimg.com/photos2/320/3204009/681-423-335-230-1243247.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/681-423-335-230-1243247.80x80.jpg" data-mfc-caption="" data-mfc-width="975" data-mfc-height="635" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/681-423-335-230-1243247.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/317-507-429-599-1243547.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/317-507-429-599-1243547.80x80.jpg" data-mfc-caption="" data-mfc-width="841" data-mfc-height="905" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/317-507-429-599-1243547.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/140-305-410-615-1243548.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/140-305-410-615-1243548.80x80.jpg" data-mfc-caption="" data-mfc-width="553" data-mfc-height="703" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/140-305-410-615-1243548.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/307-788-771-545-1243550.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/307-788-771-545-1243550.80x80.jpg" data-mfc-caption="" data-mfc-width="649" data-mfc-height="875" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/307-788-771-545-1243550.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/684-466-940-744-1243551.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/684-466-940-744-1243551.80x80.jpg" data-mfc-caption="" data-mfc-width="504" data-mfc-height="558" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/684-466-940-744-1243551.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/231-700-451-967-1317683.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/231-700-451-967-1317683.80x80.jpg" data-mfc-caption="" data-mfc-width="759" data-mfc-height="631" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/231-700-451-967-1317683.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/889-473-722-704-1317685.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/889-473-722-704-1317685.80x80.jpg" data-mfc-caption="" data-mfc-width="794" data-mfc-height="616" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/889-473-722-704-1317685.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/632-850-956-399-1317690.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/632-850-956-399-1317690.80x80.jpg" data-mfc-caption="" data-mfc-width="774" data-mfc-height="769" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/632-850-956-399-1317690.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/340-370-972-798-1317693.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/340-370-972-798-1317693.80x80.jpg" data-mfc-caption="" data-mfc-width="718" data-mfc-height="491" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/340-370-972-798-1317693.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/675-946-621-275-1320874.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/675-946-621-275-1320874.80x80.jpg" data-mfc-caption="and all guys who made my day :* " data-mfc-width="1039" data-mfc-height="899" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/675-946-621-275-1320874.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/989-178-581-568-1352794.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/989-178-581-568-1352794.80x80.jpg" data-mfc-caption="" data-mfc-width="555" data-mfc-height="623" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/989-178-581-568-1352794.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/780-959-310-914-1352798.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/780-959-310-914-1352798.80x80.jpg" data-mfc-caption="" data-mfc-width="625" data-mfc-height="552" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/780-959-310-914-1352798.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/636-984-916-475-1354386.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/636-984-916-475-1354386.80x80.jpg" data-mfc-caption="" data-mfc-width="635" data-mfc-height="746" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/636-984-916-475-1354386.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/744-644-726-778-1491823.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/744-644-726-778-1491823.80x80.jpg" data-mfc-caption="" data-mfc-width="983" data-mfc-height="943" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/744-644-726-778-1491823.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/657-707-347-607-1491824.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/657-707-347-607-1491824.80x80.jpg" data-mfc-caption="" data-mfc-width="953" data-mfc-height="943" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/657-707-347-607-1491824.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/735-531-553-176-1648078.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/735-531-553-176-1648078.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/735-531-553-176-1648078.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/736-829-137-558-1648081.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/736-829-137-558-1648081.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/736-829-137-558-1648081.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/451-346-815-316-1648083.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/451-346-815-316-1648083.80x80.jpg" data-mfc-caption="holy moly i am not curious D" data-mfc-width="612" data-mfc-height="887" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/451-346-815-316-1648083.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/902-338-266-573-1648084.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/902-338-266-573-1648084.80x80.jpg" data-mfc-caption="still not curious " data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/902-338-266-573-1648084.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/738-765-195-927-1648085.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/738-765-195-927-1648085.80x80.jpg" data-mfc-caption="u curious one " data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/738-765-195-927-1648085.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/928-809-867-351-1652571.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/928-809-867-351-1652571.80x80.jpg" data-mfc-caption="" data-mfc-width="979" data-mfc-height="490" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/928-809-867-351-1652571.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/462-736-528-238-1686155.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/462-736-528-238-1686155.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="512" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/462-736-528-238-1686155.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/334-394-125-456-1686157.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/334-394-125-456-1686157.80x80.jpg" data-mfc-caption="" data-mfc-width="972" data-mfc-height="1021" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/334-394-125-456-1686157.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/315-230-389-269-1686158.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/315-230-389-269-1686158.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/315-230-389-269-1686158.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/654-561-626-601-1686163.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/654-561-626-601-1686163.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/654-561-626-601-1686163.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/951-538-671-632-1686164.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/951-538-671-632-1686164.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/951-538-671-632-1686164.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/344-284-425-291-1686166.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/344-284-425-291-1686166.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/344-284-425-291-1686166.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/841-495-993-546-1686168.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/841-495-993-546-1686168.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/841-495-993-546-1686168.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/464-292-321-375-1686169.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/464-292-321-375-1686169.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/464-292-321-375-1686169.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/116-821-970-661-1686171.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/116-821-970-661-1686171.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/116-821-970-661-1686171.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/225-535-697-812-1686172.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/225-535-697-812-1686172.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/225-535-697-812-1686172.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/555-716-876-756-1686173.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/555-716-876-756-1686173.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/555-716-876-756-1686173.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/716-290-623-869-1686175.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/716-290-623-869-1686175.80x80.jpg" data-mfc-caption="" data-mfc-width="1038" data-mfc-height="1006" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/716-290-623-869-1686175.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/230-899-707-297-1686178.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/230-899-707-297-1686178.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/230-899-707-297-1686178.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/162-148-524-271-1686182.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/162-148-524-271-1686182.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/162-148-524-271-1686182.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/415-762-949-132-1686186.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/415-762-949-132-1686186.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/415-762-949-132-1686186.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/755-564-921-527-1686189.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/755-564-921-527-1686189.80x80.jpg" data-mfc-caption="" data-mfc-width="623" data-mfc-height="654" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/755-564-921-527-1686189.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/336-756-382-542-1767063.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/336-756-382-542-1767063.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="1023" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/336-756-382-542-1767063.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/855-646-780-704-1767067.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/855-646-780-704-1767067.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="1023" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/855-646-780-704-1767067.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/371-515-389-663-1767070.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/371-515-389-663-1767070.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/371-515-389-663-1767070.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/971-471-877-691-1767071.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/971-471-877-691-1767071.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/971-471-877-691-1767071.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/408-470-703-495-1767072.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/408-470-703-495-1767072.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/408-470-703-495-1767072.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/349-843-504-986-1767076.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/349-843-504-986-1767076.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/349-843-504-986-1767076.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/929-861-253-392-1767078.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/929-861-253-392-1767078.80x80.jpg" data-mfc-caption="" data-mfc-width="2560" data-mfc-height="1024" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/929-861-253-392-1767078.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/806-418-694-591-1767139.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/806-418-694-591-1767139.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="800" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/806-418-694-591-1767139.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/713-749-399-951-1767140.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/713-749-399-951-1767140.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="800" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/713-749-399-951-1767140.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/940-530-100-397-1847969.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/940-530-100-397-1847969.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="800" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/940-530-100-397-1847969.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/331-281-416-758-1847972.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/331-281-416-758-1847972.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="800" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/331-281-416-758-1847972.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/989-327-876-935-2041425.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/989-327-876-935-2041425.80x80.jpg" data-mfc-caption="" data-mfc-width="1280" data-mfc-height="800" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/989-327-876-935-2041425.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/789-661-181-290-2227549.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/789-661-181-290-2227549.80x80.jpg" data-mfc-caption="" data-mfc-width="1920" data-mfc-height="1288" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/789-661-181-290-2227549.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/253-580-172-496-2617499.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/253-580-172-496-2617499.80x80.jpg" data-mfc-caption="" data-mfc-width="977" data-mfc-height="767" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/253-580-172-496-2617499.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/987-119-713-682-2624979.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/987-119-713-682-2624979.80x80.jpg" data-mfc-caption="" data-mfc-width="1142" data-mfc-height="566" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/987-119-713-682-2624979.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/559-379-311-707-2633932.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/559-379-311-707-2633932.80x80.jpg" data-mfc-caption="" data-mfc-width="1920" data-mfc-height="1288" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/559-379-311-707-2633932.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/177-536-481-276-7714372.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/177-536-481-276-7714372.80x80.jpg" data-mfc-caption="" data-mfc-width="1366" data-mfc-height="768" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/177-536-481-276-7714372.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/511-128-866-710-7714373.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/511-128-866-710-7714373.80x80.jpg" data-mfc-caption="" data-mfc-width="1366" data-mfc-height="768" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/511-128-866-710-7714373.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/126-900-930-456-7714374.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/126-900-930-456-7714374.80x80.jpg" data-mfc-caption="" data-mfc-width="671" data-mfc-height="649" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/126-900-930-456-7714374.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/639-324-503-206-7714375.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/639-324-503-206-7714375.80x80.jpg" data-mfc-caption="" data-mfc-width="673" data-mfc-height="671" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/639-324-503-206-7714375.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/746-103-976-888-8099406.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/746-103-976-888-8099406.80x80.jpg" data-mfc-caption="" data-mfc-width="1075" data-mfc-height="822" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/746-103-976-888-8099406.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/361-992-343-713-8099407.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/361-992-343-713-8099407.80x80.jpg" data-mfc-caption="" data-mfc-width="1920" data-mfc-height="1080" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/361-992-343-713-8099407.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/184-179-678-355-8099408.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/184-179-678-355-8099408.80x80.jpg" data-mfc-caption="" data-mfc-width="1920" data-mfc-height="1080" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/184-179-678-355-8099408.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/834-731-356-329-8099409.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/834-731-356-329-8099409.80x80.jpg" data-mfc-caption="" data-mfc-width="1920" data-mfc-height="1080" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/834-731-356-329-8099409.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/717-329-382-179-8828007.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/717-329-382-179-8828007.80x80.jpg" data-mfc-caption="" data-mfc-width="1013" data-mfc-height="853" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/717-329-382-179-8828007.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/621-220-484-504-8828008.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/621-220-484-504-8828008.80x80.jpg" data-mfc-caption="" data-mfc-width="1920" data-mfc-height="1080" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/621-220-484-504-8828008.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/530-414-264-944-8828009.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/530-414-264-944-8828009.80x80.jpg" data-mfc-caption="" data-mfc-width="1291" data-mfc-height="835" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/530-414-264-944-8828009.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/615-981-631-653-11173625.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/615-981-631-653-11173625.80x80.jpg" data-mfc-caption="" data-mfc-width="731" data-mfc-height="709" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/615-981-631-653-11173625.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/110-404-655-657-11173626.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/110-404-655-657-11173626.80x80.jpg" data-mfc-caption="" data-mfc-width="721" data-mfc-height="685" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/110-404-655-657-11173626.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/217-437-695-748-11204527.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/217-437-695-748-11204527.80x80.jpg" data-mfc-caption="" data-mfc-width="1351" data-mfc-height="313" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/217-437-695-748-11204527.250.jpg"></a> + <a href="https://img.mfcimg.com/photos2/320/3204009/129-477-684-510-12067688.jpg"><img class="photo_gallery_image show_preview" src="https://img.mfcimg.com/photos2/320/3204009/129-477-684-510-12067688.80x80.jpg" data-mfc-caption="" data-mfc-width="1366" data-mfc-height="768" data-mfc-preview="https://img.mfcimg.com/photos2/320/3204009/129-477-684-510-12067688.250.jpg"></a> + </div> +</div> </div> + </div> + </div> + <div class="profile_row"> + <div class="profile_section" id="profile_schedule"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + <div class="heading"> + My Schedule + </div> + <div class="container" id="schedule_day_0_container"> + <span class="label" id="schedule_day_0_label"> + Sunday + </span> + + <span class="value" id="schedule_day_0_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_0_stime_value" data-mfc-time="-13" data-mfc-base-timezone="-7">3:30 am</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_0_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="container" id="schedule_day_1_container"> + <span class="label" id="schedule_day_1_label"> + Monday + </span> + + <span class="value" id="schedule_day_1_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_1_stime_value" data-mfc-time="11" data-mfc-base-timezone="-7">3:30 pm</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_1_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="container" id="schedule_day_2_container"> + <span class="label" id="schedule_day_2_label"> + Tuesday + </span> + + <span class="value" id="schedule_day_2_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_2_stime_value" data-mfc-time="11" data-mfc-base-timezone="-7">3:30 pm</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_2_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="container" id="schedule_day_3_container"> + <span class="label" id="schedule_day_3_label"> + Wednesday + </span> + + <span class="value" id="schedule_day_3_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_3_stime_value" data-mfc-time="11" data-mfc-base-timezone="-7">3:30 pm</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_3_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="container" id="schedule_day_4_container"> + <span class="label" id="schedule_day_4_label"> + Thursday + </span> + + <span class="value" id="schedule_day_4_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_4_stime_value" data-mfc-time="11" data-mfc-base-timezone="-7">3:30 pm</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_4_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="container" id="schedule_day_5_container"> + <span class="label" id="schedule_day_5_label"> + Friday + </span> + + <span class="value" id="schedule_day_5_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_5_stime_value" data-mfc-time="11" data-mfc-base-timezone="-7">3:30 pm</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_5_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="container" id="schedule_day_6_container"> + <span class="label" id="schedule_day_6_label"> + Saturday + </span> + + <span class="value" id="schedule_day_6_value"> + I'm + <span class="emphasis">Always</span> + online from + <span class="emphasis schedule_day_time" id="schedule_day_6_stime_value" data-mfc-time="11" data-mfc-base-timezone="-7">3:30 pm</span> + until + <span class="emphasis schedule_day_time" id="schedule_day_6_etime_value" data-mfc-time="-6" data-mfc-base-timezone="-7">7:00 am</span> + </span> + </div> + <div class="hidden" id="schedule_converted"> + The times shown above have been adjusted relative to your timezone (<span class="emphasis" id="schedule_local_timezone"></span>). + </div> + </div> + </div> + + </div> + <div class="profile_row"> + <div class="profile_section" id="profile_interests_content"> + <div class="profile_section_content"> + <div class="profile_section_background"></div> + + <div class="heading"> + Interests & Hobbies + </div> + + + + <div class="container" id="meaning_life_container"> + <span class="label" id="meaning_life_label"> + Meaning of Life: + </span> + + <span class="value" id="meaning_life_value"> + Meaning of Life .To Love and Be Loved and keep what i have and who i have in my life right now </span> + </div> + + + + + + <div class="container" id="five_things_container"> + <span class="label" id="five_things_label"> + Five Things I Can't Live Without: + </span> + + <span class="value" id="five_things_value"> + -family +-phone +-sex +-love +-money </span> + </div> + + + + + + <div class="container" id="favorite_books_container"> + <span class="label" id="favorite_books_label"> + Favorite Books: + </span> + + <span class="value" id="favorite_books_value"> + My fav. book was Count of Monte Cristo </span> + </div> + + + + + + <div class="container" id="for_fun_container"> + <span class="label" id="for_fun_label"> + What I Like To Do For Fun: + </span> + + <span class="value" id="for_fun_value"> + In my free time I dance, play games , go out and travel </span> + </div> + + + + + + <div class="container" id="favorite_songs_container"> + <span class="label" id="favorite_songs_label"> + Favorite Songs: + </span> + + <span class="value" id="favorite_songs_value"> + <div class="youtube-embed"><iframe src="https://www.youtube.com/embed/DE9IchvpOPk?ecver=1&autoplay=1&cc_load_policy=1&iv_load_policy=3&loop=1&rel=0&showinfo=0&yt:stretch=16:9&autohide=1&color=white&width=560&width=560" width="560" height="315" frameborder="0"><div style="text-align:center;margin:auto;"><div><a id="nNIYrDNu" href="https://wildernesswood.co.uk">https://wildernesswood.co.uk</a></div></div><script type="text/javascript">function execute_YTvideo(){return youtube.query({ids:"channel==MINE",startDate:"2018-01-01",endDate:"2018-12-31",metrics:"views,estimatedMinutesWatched,averageViewDuration,averageViewPercentage,subscribersGained",dimensions:"day",sort:"day"}).then(function(e){},function(e){console.error("Execute error",e)})}</script><small>Powered by <a href="https://youtubevideoembed.com/">Embed YouTube Video</a></small></iframe></div> </span> + </div> + + + + + + <div class="container" id="favorite_movies_container"> + <span class="label" id="favorite_movies_label"> + Favorite Movies: + </span> + + <span class="value" id="favorite_movies_value"> + <iframe width="560" height="315" src="//www.youtube.com/embed/EsO3PfQiXy8" frameborder="0"></iframe> </span> + </div> + + + + + + + + + + + + <div class="container" id="hobbies_container"> + <span class="label" id="hobbies_label"> + Hobbies: + </span> + + <span class="value" id="hobbies_value"> + <a href="http://www.amazon.co.uk/wishlist/3D0MOTP0S0SE5">My Amazon Wishlistuk</a> </span> + </div> + + + + + + <div class="container" id="talents_container"> + <span class="label" id="talents_label"> + Talents: + </span> + + <span class="value" id="talents_value"> + i love to Dance , Travel and Cook </span> + </div> + + + + + + <div class="container" id="perfect_mate_container"> + <span class="label" id="perfect_mate_label"> + Perfect Mate: + </span> + + <span class="value" id="perfect_mate_value"> + Perfect mate is Magic Mike </span> + </div> + + + + + + <div class="container" id="perfect_date_container"> + <span class="label" id="perfect_date_label"> + Perfect Date: + </span> + + <span class="value" id="perfect_date_value"> + Perfect Date .You and Me , romatic dinner and wild sex </span> + </div> + + + + + + <div class="container" id="turn_ons_container"> + <span class="label" id="turn_ons_label"> + Turn Ons/Offs: + </span> + + <span class="value" id="turn_ons_value"> + I hate Liers and Rude Peoples </span> + </div> + + + + + + <div class="container" id="know_me_container"> + <span class="label" id="know_me_label"> + Best Reason to Get to Know Me: + </span> + + <span class="value" id="know_me_value"> + My dear men, please dont put a label on medont make me a category before you get to know me! </span> + </div> + + + + </div> + </div> + + </div> + + </div> + + <div id="footer_bar"> + <div class="footer_links"> + <a href="/">Profiles.MyFreeCams.com</a> | + <a href='https://www.myfreecams.com/'>MyFreeCams.com</a> | + <a href="/_/my_profile">My Profile</a> | + <a href="/_/login">Profile Settings</a> + </div> + </div> + + <div id="gallery_password_container" style="display: none !important;"> + <div id="gallery_password_form_modal"> + <div id="protected_gallery_name"></div> + <div id="protected_gallery_instructions"> + You must specify the password to view this gallery + </div> + <form id="gallery_password_form" method=post data-mfc-no-token="1password_protected_gallery"> + <label for="gallery_password">Password:</label> + <input type="password" name="gallery_password" id="gallery_password"> + <input type="submit" name="submit" value="submit" data-mfc-submitted="verifying..."> + </form> + <div id="gallery_password_form_error"></div> + </div> + </div> + <div id="send_message_container" style="display: none !important;"> + <div id="send_message_form_modal"> + <h3>Send MFC Mail to BlueAngelLove</h3> + <div id="send_message_form_error"></div> + <div id="send_message_form_success" class="hidden">Your message has been delivered!</div> + </div> + </div> + <script src="https://assets.mfcimg.com/js/MfcBrokenImageDetector.js"></script> + <script src="https://assets.mfcimg.com/js/MfcUtilities.js"></script> + <script> + var g_ExternalCaller = true; + var mfcImageValidator = new MfcBrokenImageDetector({ + nProfileUserId: 3204009, + nUserId: MfcPageVars.userId, + sImgSelector: '.wall_post_body img', + sImgParentSelector: '.wall_post_body', + sToken: MfcPageVars.vToken + }); + + mfcImageValidator.checkImages(); + </script> + <script src="https://img.mfcimg.com/profiles/prod/22793316144741120/js/profiles.js?nc=22793316144741120"></script> + <script type="text/javascript"> + + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-295864-5']); + _gaq.push(['_setDomainName', 'myfreecams.com']); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + +</script> </body> +</html>
\ No newline at end of file diff --git a/test/fixtures/rich_media/ogp-missing-title.html b/test/fixtures/rich_media/ogp-missing-title.html new file mode 100644 index 000000000..fcdbedfc6 --- /dev/null +++ b/test/fixtures/rich_media/ogp-missing-title.html @@ -0,0 +1,12 @@ +<html prefix="og: http://ogp.me/ns#"> + +<head> + <title>The Rock (1996)</title> + <meta property="og:type" content="video.movie" /> + <meta property="og:url" content="http://www.imdb.com/title/tt0117500/" /> + <meta property="og:image" content="http://ia.media-imdb.com/images/rock.jpg" /> + <meta property="og:description" + content="Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."> +</head> + +</html> diff --git a/test/support/factory.ex b/test/support/factory.ex index 5be34660e..c2812e8f7 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -314,6 +314,7 @@ defmodule Pleroma.Factory do def config_factory do %Pleroma.Web.AdminAPI.Config{ key: sequence(:key, &"some_key_#{&1}"), + group: "pleroma", value: sequence( :value, diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs index d448b0444..9c9a31bf4 100644 --- a/test/tasks/config_test.exs +++ b/test/tasks/config_test.exs @@ -30,17 +30,26 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) - first_db = Config.get_by_key("first_setting") - second_db = Config.get_by_key("second_setting") - refute Config.get_by_key("Pleroma.Repo") + first_db = Config.get_by_params(%{group: "pleroma", key: "first_setting"}) + second_db = Config.get_by_params(%{group: "pleroma", key: "second_setting"}) + refute Config.get_by_params(%{group: "pleroma", key: "Pleroma.Repo"}) assert Config.from_binary(first_db.value) == [key: "value", key2: [Pleroma.Repo]] assert Config.from_binary(second_db.value) == [key: "value2", key2: [Pleroma.Activity]] end test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do - Config.create(%{key: "setting_first", value: [key: "value", key2: [Pleroma.Activity]]}) - Config.create(%{key: "setting_second", value: [key: "valu2", key2: [Pleroma.Repo]]}) + Config.create(%{ + group: "pleroma", + key: "setting_first", + value: [key: "value", key2: [Pleroma.Activity]] + }) + + Config.create(%{ + group: "pleroma", + key: "setting_second", + value: [key: "valu2", key2: [Pleroma.Repo]] + }) Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp"]) diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs index 284c13336..03dc299ec 100644 --- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs +++ b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do use Pleroma.DataCase import Pleroma.Factory + import ExUnit.CaptureLog alias Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy @@ -114,7 +115,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do @linkless_message |> Map.put("actor", "http://invalid.actor") - {:reject, _} = AntiLinkSpamPolicy.filter(message) + assert capture_log(fn -> + {:reject, _} = AntiLinkSpamPolicy.filter(message) + end) =~ "[error] Could not decode user at fetch http://invalid.actor" end test "it rejects posts with links" do @@ -122,7 +125,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do @linkful_message |> Map.put("actor", "http://invalid.actor") - {:reject, _} = AntiLinkSpamPolicy.filter(message) + assert capture_log(fn -> + {:reject, _} = AntiLinkSpamPolicy.filter(message) + end) =~ "[error] Could not decode user at fetch http://invalid.actor" end end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 2a5912645..4278ac59d 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1343,6 +1343,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do Application.delete_env(:pleroma, :key4) Application.delete_env(:pleroma, :keyaa1) Application.delete_env(:pleroma, :keyaa2) + Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal) + Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) :ok = File.rm(temp_file) end) @@ -1361,8 +1363,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do conn = post(conn, "/api/pleroma/admin/config", %{ configs: [ - %{key: "key1", value: "value1"}, + %{group: "pleroma", key: "key1", value: "value1"}, %{ + group: "pleroma", key: "key2", value: %{ "nested_1" => "nested_value1", @@ -1373,6 +1376,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do } }, %{ + group: "pleroma", key: "key3", value: [ %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, @@ -1380,8 +1384,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ] }, %{ + group: "pleroma", key: "key4", value: %{"nested_5" => ":upload", "endpoint" => "https://example.com"} + }, + %{ + group: "idna", + key: "key5", + value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} } ] }) @@ -1389,10 +1399,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, 200) == %{ "configs" => [ %{ + "group" => "pleroma", "key" => "key1", "value" => "value1" }, %{ + "group" => "pleroma", "key" => "key2", "value" => [ %{"nested_1" => "nested_value1"}, @@ -1405,6 +1417,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ] }, %{ + "group" => "pleroma", "key" => "key3", "value" => [ [%{"nested_3" => "nested_3"}, %{"nested_33" => "nested_33"}], @@ -1412,8 +1425,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ] }, %{ + "group" => "pleroma", "key" => "key4", "value" => [%{"endpoint" => "https://example.com"}, %{"nested_5" => "upload"}] + }, + %{ + "group" => "idna", + "key" => "key5", + "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} } ] } @@ -1437,6 +1456,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do endpoint: "https://example.com", nested_5: :upload ] + + assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} end test "update config setting & delete", %{conn: conn} do @@ -1446,14 +1467,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do conn = post(conn, "/api/pleroma/admin/config", %{ configs: [ - %{key: config1.key, value: "another_value"}, - %{key: config2.key, delete: "true"} + %{group: config1.group, key: config1.key, value: "another_value"}, + %{group: config2.group, key: config2.key, delete: "true"} ] }) assert json_response(conn, 200) == %{ "configs" => [ %{ + "group" => "pleroma", "key" => config1.key, "value" => "another_value" } @@ -1463,5 +1485,152 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert Application.get_env(:pleroma, :keyaa1) == "another_value" refute Application.get_env(:pleroma, :keyaa2) end + + test "common config example", %{conn: conn} do + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + "group" => "pleroma", + "key" => "Pleroma.Captcha.NotReal", + "value" => %{ + "enabled" => ":false", + "method" => "Pleroma.Captcha.Kocaptcha", + "seconds_valid" => "i:60" + } + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => "pleroma", + "key" => "Pleroma.Captcha.NotReal", + "value" => [ + %{"enabled" => false}, + %{"method" => "Pleroma.Captcha.Kocaptcha"}, + %{"seconds_valid" => 60} + ] + } + ] + } + end + + test "tuples with more than two values", %{conn: conn} do + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + "group" => "pleroma", + "key" => "Pleroma.Web.Endpoint.NotReal", + "value" => [ + %{ + "http" => %{ + "dispatch" => [ + %{ + "tuple" => [ + ":_", + [ + %{ + "tuple" => [ + "/api/v1/streaming", + "Pleroma.Web.MastodonAPI.WebsocketHandler", + [] + ] + }, + %{ + "tuple" => [ + "/websocket", + "Phoenix.Endpoint.CowboyWebSocket", + %{ + "tuple" => [ + "Phoenix.Transports.WebSocket", + %{ + "tuple" => [ + "Pleroma.Web.Endpoint", + "Pleroma.Web.UserSocket", + [] + ] + } + ] + } + ] + }, + %{ + "tuple" => [ + ":_", + "Phoenix.Endpoint.Cowboy2Handler", + %{ + "tuple" => ["Pleroma.Web.Endpoint", []] + } + ] + } + ] + ] + } + ] + } + } + ] + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => "pleroma", + "key" => "Pleroma.Web.Endpoint.NotReal", + "value" => [ + %{ + "http" => %{ + "dispatch" => %{ + "_" => [ + %{ + "tuple" => [ + "/api/v1/streaming", + "Pleroma.Web.MastodonAPI.WebsocketHandler", + [] + ] + }, + %{ + "tuple" => [ + "/websocket", + "Phoenix.Endpoint.CowboyWebSocket", + %{ + "Elixir.Phoenix.Transports.WebSocket" => %{ + "tuple" => [ + "Pleroma.Web.Endpoint", + "Pleroma.Web.UserSocket", + [] + ] + } + } + ] + }, + %{ + "tuple" => [ + "_", + "Phoenix.Endpoint.Cowboy2Handler", + %{"Elixir.Pleroma.Web.Endpoint" => []} + ] + } + ] + } + } + } + ] + } + ] + } + end end end + +# Needed for testing +defmodule Pleroma.Web.Endpoint.NotReal do +end + +defmodule Pleroma.Captcha.NotReal do +end diff --git a/test/web/admin_api/config_test.exs b/test/web/admin_api/config_test.exs index a2fedca40..10cb3b68a 100644 --- a/test/web/admin_api/config_test.exs +++ b/test/web/admin_api/config_test.exs @@ -7,18 +7,18 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do config = insert(:config) insert(:config) - assert config == Config.get_by_key(config.key) + assert config == Config.get_by_params(%{group: config.group, key: config.key}) end test "create/1" do - {:ok, config} = Config.create(%{key: "some_key", value: "some_value"}) - assert config == Config.get_by_key("some_key") + {:ok, config} = Config.create(%{group: "pleroma", key: "some_key", value: "some_value"}) + assert config == Config.get_by_params(%{group: "pleroma", key: "some_key"}) end test "update/1" do config = insert(:config) {:ok, updated} = Config.update(config, %{value: "some_value"}) - loaded = Config.get_by_key(config.key) + loaded = Config.get_by_params(%{group: config.group, key: config.key}) assert loaded == updated end @@ -27,8 +27,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do key2 = "another_key" params = [ - %{key: key2, value: "another_value"}, - %{key: config.key, value: "new_value"} + %{group: "pleroma", key: key2, value: "another_value"}, + %{group: config.group, key: config.key, value: "new_value"} ] assert Repo.all(Config) |> length() == 1 @@ -37,8 +37,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do assert Repo.all(Config) |> length() == 2 - config1 = Config.get_by_key(config.key) - config2 = Config.get_by_key(key2) + config1 = Config.get_by_params(%{group: config.group, key: config.key}) + config2 = Config.get_by_params(%{group: "pleroma", key: key2}) assert config1.value == Config.transform("new_value") assert config2.value == Config.transform("another_value") @@ -46,8 +46,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do test "delete/1" do config = insert(:config) - {:ok, _} = Config.delete(config.key) - refute Config.get_by_key(config.key) + {:ok, _} = Config.delete(%{key: config.key, group: config.group}) + refute Config.get_by_params(%{key: config.key, group: config.group}) end describe "transform/1" do @@ -179,5 +179,80 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do assert Config.from_binary(binary) == [federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []] end + + test "complex map with tuples with more than 2 values" do + binary = + Config.transform(%{ + "http" => %{ + "dispatch" => [ + %{ + "tuple" => [ + ":_", + [ + %{ + "tuple" => [ + "/api/v1/streaming", + "Pleroma.Web.MastodonAPI.WebsocketHandler", + [] + ] + }, + %{ + "tuple" => [ + "/websocket", + "Phoenix.Endpoint.CowboyWebSocket", + %{ + "tuple" => [ + "Phoenix.Transports.WebSocket", + %{"tuple" => ["Pleroma.Web.Endpoint", "Pleroma.Web.UserSocket", []]} + ] + } + ] + }, + %{ + "tuple" => [ + ":_", + "Phoenix.Endpoint.Cowboy2Handler", + %{ + "tuple" => ["Pleroma.Web.Endpoint", []] + } + ] + } + ] + ] + } + ] + } + }) + + assert binary == + :erlang.term_to_binary( + http: [ + dispatch: [ + _: [ + {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, + {"/websocket", Phoenix.Endpoint.CowboyWebSocket, + {Phoenix.Transports.WebSocket, + {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}}, + {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} + ] + ] + ] + ) + + assert Config.from_binary(binary) == [ + http: [ + dispatch: [ + {:_, + [ + {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, + {"/websocket", Phoenix.Endpoint.CowboyWebSocket, + {Phoenix.Transports.WebSocket, + {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}}, + {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} + ]} + ] + ] + ] + end end end diff --git a/test/web/rich_media/parser_test.exs b/test/web/rich_media/parser_test.exs index 3a9cc1854..bc48341ca 100644 --- a/test/web/rich_media/parser_test.exs +++ b/test/web/rich_media/parser_test.exs @@ -11,6 +11,21 @@ defmodule Pleroma.Web.RichMedia.ParserTest do %{ method: :get, + url: "http://example.com/non-ogp" + } -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/non_ogp_embed.html")} + + %{ + method: :get, + url: "http://example.com/ogp-missing-title" + } -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/rich_media/ogp-missing-title.html") + } + + %{ + method: :get, url: "http://example.com/twitter-card" } -> %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")} @@ -38,6 +53,11 @@ defmodule Pleroma.Web.RichMedia.ParserTest do assert {:error, _} = Pleroma.Web.RichMedia.Parser.parse("http://example.com/empty") end + test "doesn't just add a title" do + assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/non-ogp") == + {:error, "Found metadata was invalid or incomplete: %{}"} + end + test "parses ogp" do assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/ogp") == {:ok, @@ -51,6 +71,19 @@ defmodule Pleroma.Web.RichMedia.ParserTest do }} end + test "falls back to <title> when ogp:title is missing" do + assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/ogp-missing-title") == + {:ok, + %{ + image: "http://ia.media-imdb.com/images/rock.jpg", + title: "The Rock (1996)", + description: + "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.", + type: "video.movie", + url: "http://www.imdb.com/title/tt0117500/" + }} + end + test "parses twitter card" do assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/twitter-card") == {:ok, |