...

суббота, 22 сентября 2018 г.

OAuth Authorization Provider для asp net core

Начал изучать asp.net core и первое что пытался найти это некое подобие «OAuthAuthorizationServerProvider» для реализации генерации тикета и «IAuthenticationTokenProvider» для реализаций рефреш токена как в обычном asp.net, но не нашел. Не исключено, что плохо искал, и может появится коммент типа «вот обкатанная библиотека для этого дела».

Хорошо, что можно довольно просто написать свой Middleware для обработки запросов, и связать его с некоторой реализацией провайдера через «сервисы» в ConfigureServices.

Итак, мне нужно что бы были методы для получения токена по логину и паролю по адресу "/token" и метод по получению токена по рефреш-токену.

   public interface IOAuthProvider
    {
        Task ByPassword(OAuthProviderContext oAuthProviderContext);
        Task ByRefreshToken(OAuthProviderContext oAuthProviderContext);
    }

То есть в конечном итоге реализовав один этот интерфейс и связав его в ConfigureServices авторизация должна работать.

В параметре «OAuthProviderContext» будут храниться данные контекста для авторизации:

    public class OAuthProviderContext
    {
        public bool HasError { get; private set; }
        public string Error { get; private set; }
        public string AccessToken { get; private set; }
        public string RefreshToken { get; set; }

        public string ClientId { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public void SetError(string error)
        {
            Error = error;
            HasError = true;
        }
        public void SetToken(string access_token, string refresh_token)
        {
            AccessToken = access_token;
            RefreshToken = refresh_token;
        }
    }

Теперь надо сделать middleware, которое будет работать с будущими реализациями IOAuthProvider:
class OAuthProviderMiddleware
    {
        RequestDelegate _next;
        IOAuthProvider _oAuthProvider;       

        public OAuthProviderMiddleware(RequestDelegate next, IOAuthProvider oAuthProvider)
        {
            _next = next;
            _oAuthProvider = oAuthProvider;
        }
        public async Task Invoke(HttpContext context)
        {
            OAuthProviderContext _oAuthProviderContext;

            string path = context.Request.Path.Value.ToLower().Trim();

            bool isPost = context.Request.Method.ToLower() == "post";

            if (path == "/token" && isPost)
            {
                var form = context.Request.Form;

                if (!form.ContainsKey("grant_type")) {
                    await context.BadRequest("invalid grant_type");
                    return;
                }
                if (!form.ContainsKey("client_id"))
                {
                    await context.BadRequest("invalid client_id");
                    return;
                }

                string grant_type = form["grant_type"];
                string client_id = form["client_id"];

                switch (grant_type)
                {
                    case "password":
                        {
                            if (!form.ContainsKey("username"))
                            {
                                await context.BadRequest("invalid username");
                                return;
                            }
                            if (!form.ContainsKey("password"))
                            {
                                await context.BadRequest("invalid password");
                                return;
                            }

                            string username = form["username"];
                            string password = form["password"];

                            _oAuthProviderContext = new OAuthProviderContext()
                            {
                                ClientId = client_id,
                                Username = username,
                                Password = password
                            };


                            await _oAuthProvider.ByPassword(_oAuthProviderContext);

                            if (_oAuthProviderContext.HasError)
                            {
                                await context.BadRequest(_oAuthProviderContext.Error);
                                return;
                            }
                            else
                            {
                                await context.WriteToken(_oAuthProviderContext);
                                return;
                            }

                        };
                    case "refresh_token":
                        {
                            if (!form.ContainsKey("refresh_token"))
                            {
                                await context.BadRequest("invalid refresh_token");
                                return;
                            }

                            string refresh_token = form["refresh_token"];

                            _oAuthProviderContext = new OAuthProviderContext()
                            {
                                ClientId = client_id,
                                RefreshToken = refresh_token
                            };

                            await _oAuthProvider.ByRefreshToken(_oAuthProviderContext);

                            if (_oAuthProviderContext.HasError)
                            {
                                await context.BadRequest(_oAuthProviderContext.Error);                                
                                return;
                            }
                            else
                            {
                                await context.WriteToken(_oAuthProviderContext);
                                return;
                            }
                        };
                    default:
                        {
                            await context.BadRequest("invalid grant_type");
                            return;
                        };
                }
            }
            else
            {
                await _next.Invoke(context);
            }
        }
    }

    public static class OAuthExtensions
    {
        public static IApplicationBuilder UseOAuth(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<OAuthProviderMiddleware>();
        }

        internal static async Task BadRequest(this HttpContext context, string Error)
        {
            context.Response.StatusCode = 400;
            await context.Response.WriteAsync(Error);
        }

        internal static async Task WriteToken(this HttpContext context, OAuthProviderContext _oAuthProviderContext)
        {
            context.Response.ContentType = "application/json";
            await context.Response.WriteAsync(JsonConvert.SerializeObject(new
            {
                access_token = _oAuthProviderContext.AccessToken,
                refresh_token = _oAuthProviderContext.RefreshToken
            }));
        }
    }

В Configure потом можно будет вызвать обертку
app.UseOAuth();

Далее остается написать конкретную реализацию IOAuthProvider.

Токен будет в виде JWT, а рефреш-токен рандомный byte[] массив длиной 100 представленный как Base64. В конце еще будет ссылка на код.

 public class OAuthProviderImplement : IOAuthProvider
    {
        IServiceProvider _services;
        IOptions<AuthOptions> _authOptions = null;
        Helper _helper = null;

        public OAuthProviderImplement(IServiceProvider services, IOptions<AuthOptions> authOptions, Helper helper)
        {
            _services = services;
            _authOptions = authOptions;
            _helper = helper;
        }

        public async Task ByPassword(OAuthProviderContext context)
        {
            ClaimsIdentity identity = await GetIdentity(context.Username, context.ClientId, context.Password);
            if (identity == null)
            {
                context.SetError("User not found");
                return;
            }

            string encodedJwt = CreateJWT(identity);
            string refresh_token = await CreateRefreshToken(context.ClientId, identity);

            if (refresh_token == null)
            {
                context.SetError("Error while create refresh token");
                return;
            }

            context.SetToken(encodedJwt, refresh_token);
            return;
        }

        public async Task ByRefreshToken(OAuthProviderContext context)
        {
            ProtectedTicket protectedTicket = await GrantRefreshToken(context.RefreshToken);

            if (protectedTicket == null)
            {
                context.SetError("Invalid refresh token");
                return;
            }

            if (protectedTicket.clientid != context.ClientId)
            {
                context.SetError("Invalid client id");
                return;
            }

            ClaimsIdentity identity = await GetIdentity(protectedTicket.username, protectedTicket.clientid);

            if (identity == null)
            {
                context.SetError("User not found");
                return;
            }

            string encodedJwt = CreateJWT(identity);

            context.SetToken(encodedJwt, context.RefreshToken);
            return;
        }

        string CreateJWT(ClaimsIdentity identity)
        {
            var now = DateTime.UtcNow;
            // создаем JWT-токен
            var jwt = new JwtSecurityToken(
                    issuer: _authOptions.Value.Issuer,
                    audience: _authOptions.Value.Audience,
                    notBefore: now,
                    claims: identity.Claims,
                    expires: now.Add(TimeSpan.FromSeconds(_authOptions.Value.LifetimeSeconds)),
                    signingCredentials: new SigningCredentials(_authOptions.Value.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256));

            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

            return encodedJwt;
        }

        async Task<ClaimsIdentity> GetIdentity(string username, string clientid, string password = null)
        {
            using (var serviceScope = _services.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                IAuthRepository _repo = serviceScope.ServiceProvider.GetService<IAuthRepository>();

                ApplicationUser user = null;
                if (password != null)
                {
                    user = await _repo.FindUser(username, password);
                }
                else
                {
                    user = await _repo.FindUser(username);
                }

                if (user != null)
                {
                    var claims = new List<Claim>
                {
                    new Claim(ClaimsIdentity.DefaultNameClaimType, user.UserName)
                };

                    foreach (var r in await _repo.GetRoles(user))
                    {
                        claims.Add(new Claim(ClaimsIdentity.DefaultRoleClaimType, r));
                    }

                    claims.Add(new Claim("client_id", clientid));

                    ClaimsIdentity claimsIdentity = new ClaimsIdentity(
                        claims,
                        "Password",
                        ClaimsIdentity.DefaultNameClaimType,
                        ClaimsIdentity.DefaultRoleClaimType);

                    return claimsIdentity;
                }
                else
                {

                }

                // если пользователя не найдено
                return null;
            }
        }

        async Task<string> CreateRefreshToken(string clientid, ClaimsIdentity claimsIdentity)
        {
            using (var serviceScope = _services.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                IAuthRepository _repo = serviceScope.ServiceProvider.GetService<IAuthRepository>();
                Client client = _repo.FindClient(clientid);

                var refreshTokenId = _helper.GetHash(_helper.GenerateRandomCryptographicKey(100));

                var refreshTokenLifeTime = client.RefreshTokenLifeTime;

                var now = DateTime.UtcNow;

                var token = new RefreshToken()
                {
                    Id = _helper.GetHash(refreshTokenId),
                    ClientId = clientid,
                    Subject = claimsIdentity.Name,
                    IssuedUtc = now,
                    ExpiresUtc = now.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
                };

                token.ProtectedTicket = JsonConvert.SerializeObject(new ProtectedTicket { clientid = clientid, username = claimsIdentity.Name });

                var result = await _repo.AddRefreshToken(token);

                if (result)
                {
                    return refreshTokenId;
                }

                return null;
            }
        }

        async Task<ProtectedTicket> GrantRefreshToken(string refreshTokenId)
        {
            using (var serviceScope = _services.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                IAuthRepository _repo = serviceScope.ServiceProvider.GetService<IAuthRepository>();
                string hashedTokenId = _helper.GetHash(refreshTokenId);
                ProtectedTicket protectedTicket = null;

                var refreshToken = await _repo.FindRefreshToken(hashedTokenId);

                if (refreshToken != null)
                {
                    //Get protectedTicket from refreshToken class
                    protectedTicket = JsonConvert.DeserializeObject<ProtectedTicket>(refreshToken.ProtectedTicket);

                    return protectedTicket;
                }
                else
                {
                    return null;
                }
            }
        }
    }

Теперь обработаются запросы:
post "/token" с данными в body: grant_type="password", client_id="ngAuth", username="admin", password="123"
и
post "/token" с данными в body: grant_type="refresh_token", client_id="ngAuth", refresh_token="dgDrVQHylvHmi8QZ5oThVjWyqdrLYKhp1/XHsIJI65g="

На этом все, вообщем напишите кто че думает.

Весь код

Let's block ads! (Why?)

[Из песочницы] Определяем спелость арбуза с помощью Keras: полный цикл, от идеи до программы на Google Play

С чего все началось


Все началось с Эппл Маркета — я обнаружил, что у них есть программа, позволяющая определить спелость арбуза. Программа… странная. Чего стоит, хотя бы, предложение постучать по арбузу не костяшками пальцев, а… телефоном! Тем не менее, мне захотелось повторить это достижение на более привычной платформе Андроид.

Выбор инструментов


Задача наша решается несколькими способами, и если честно, мне пришлось приложить немалые усилия, чтобы не пойти «простым» путем. То есть, взять преобразования Фурье, вейвлеты и редактор сигналов. Однако, я хотел получить опыт работы с нейросетями, так что пусть сети и занимаются анализом данных.

В качестве библиотеки для создания и обучения нейросетей был выбран Керас — гугловская надстройка над TensorFlow и Theano. Вообще, если вы только начинаете работу с сетями глубокого обучения, лучше инструмента вам не найти. С одной стороны, Керас — мощный инструмент, оптимизированный по скорости, памяти и железу (да, он умеет работать на видеокартах и их кластерах). С другой — всё, что можно «спрятать» от пользователя, там спрятано, так что вам не придется ломать голову над стыковкой слоев нейросети, например. Очень удобно.

Как Керас, так и нейросети вообще, требуют знания Питона — этот язык, подобно змее обвил… извините, наболело. Короче, без Питона в современный Deep Learning соваться не стоит. К счастью, Питон можно изучить за две недели, в крайнем случае — за месяц.

К Питону вам потребуются еще некоторые библиотеки, но это уже мелочи — я имею в виду, если уж вы справились с самим Питоном. Потребуется знакомство (весьма поверхностное) с NumPy, PyPlot и возможно, еще с парой библиотек, из которых мы возьмем буквально по паре функций. Не сложно. Правда.

Ну и в завершение замечу, что упоминавшиеся выше кластеры видеокарт нам не потребуются — наша задача нормально решается с помощью компьютерного CPU — медленно, но не критично медленно.

План работы


Сначала нужно создать нейросеть — на Питоне и Керасе, под Убунту. Можно — на эмуляторе Убунты. Можно — под Виндоуз, но потраченного дополнительно времени вам хватит, чтобы упомянутую Убунту изучить, и далее работать под ней.

Следующий шаг — написание программы. Я планирую сделать это на Java под Андроид. Это будет прототип программы, в том смысле, что пользовательский интерфейс у нее будет, а вот нейросети пока что нет.

В чем же смысл написания «пустышки», спросите вы. А вот в чем: любая задача, связанная с анализом данных, рано или поздно упирается в поиск данных — для обучения нашей программы. В самом деле, сколько арбузов надо обстучать и попробовать на вкус, чтобы нейросеть смогла на этих данных построить достоверную модель? Сотню? Больше?

Здесь нам и поможет наша программа: заливаем ее на Google Play, раздаем (ладно, навязываем, выкручивая руки) всем друзьям, которым не повезло иметь телефон с Андроидом, и данные, тонюсеньким ручейком, начинают стекаться… а кстати, куда?

Следующий шаг — написание серверной программы, принимающей данные от нашего андроид клиента. Правда, эта серверная программа очень проста, я все закончил минут за двадцать. Но, тем не менее, это отдельный этап.

Наконец, данных достаточно. Обучаем нейросеть.

Портируем нейросеть на Java и выпускаем обновление нашей программы.

Профит. Хотя нет. Программа была бесплатной. Только опыт и набитые шишки.

Создание нейросети


Работа с аудио, каковым, безусловно, является постукивание по арбузу, это либо рекуррентные нейросети, либо так называемая одномерная конволюционная сеть. Причем, в последнее время конволюционные сети однозначно лидируют, вытесняя рекуррентные. Идея конволюционной сети заключается в том, что по массиву данных — графику «интерсивность звука — время» — скользит окошко, и вместо анализа сотен тысяч сэмплов, мы работаем только с тем, что в окошко попадает. Следующие слои объединяют и анализируют результаты работы этого слоя.

Чтобы было понятнее, представьте, что вам надо найти на фото морского пейзажа чайку. Вы сканируете картину — «окошко» вашего внимания движется вдоль воображаемых строк и столбцов, в поисках белой галочки. Именно так работает конволюционная 2D сеть, одномерная же сканирует вдоль одной координаты — оптимальный выбор, если мы имеем дело со звуковым сигналом.

Отмечу, однако, что зацикливаться на 1D сетях не обязательно. В качестве упражнения, я построил график звука и анализировал полученный битмап как картинку — с помощью 2d конволюционной сети. К моему удивлению, результат получился не хуже, чем при анализе «сырых одномерных» данных.

Используемая сеть имела следующую структуру:

model = Sequential()
model.add(Conv1D(filters=32, kernel_size=512, strides=3, 
        padding='valid', use_bias=False, input_shape=(nSampleSize, 1), name='c1d', 
        activation='relu'))
model.add(Activation('relu', input_shape=(nSampleSize, 1)))
model.add(MaxPooling1D(pool_size=(2)))

model.add(Conv1D(32, (3)))
model.add(Activation('relu'))
model.add(MaxPooling1D(pool_size=(2)))

model.add(Conv1D(64, (3)))
model.add(Activation('relu'))
model.add(MaxPooling1D(pool_size=(2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nNumOfOutputs)) #1))
model.add(Activation('sigmoid'))

model.compile(loss='mean_squared_error',
        optimizer='adam',
        metrics=['accuracy'])


У этой сети два выходных значения (она предсказывает две величины): сладость и спелость. Сладость бывает 0 (несладкий), 1 (нормальный) и 2 (превосходный), а спелость, соответственно, 0 — слишком твердый, 1 — то, что надо, и 2 — перезрелый, как вата с песком.

Оценки для тестовой выборки выставляются человеком, как именно — мы поговорим в разделе, посвященном программе для Андроид. Задача нейросети — предсказать, какую для данного арбуза (по записи постукивания) оценку поставит человек.

Написание программы


Я уже упоминал, что программа должна выйти в виде двух версий. Первая, предварительная, честно предупреждает пользователя, что ее предсказания — полный бред. Зато она позволяет пользователю записать стук по арбузу, выставить оценку вкусовых качеств этого арбуза и переслать по Интернет автору программы. То есть, первая версия просто собирает данные.

Вот страничка программы на Google Play, разумеется, программа бесплатна.

Что она делает:

1. Нажимаем кнопку с микрофоном и начинается запись. У вас есть пять секунд, чтобы три раза стукнуть по арбузу — тук-тук-тук. Кнопка с арбузом делает «предсказание», и ее мы пока не трогаем.

Примечание — если на Гугле старая версия, то запись и предсказание совмещены в кнопке с арбузом, а кнопки с микрофоном нету.

image

2. Сохраненный файл — временный, и будет перезаписан при следующем нажатии кнопки записи. Это позволяет повторить постукивание, если кто-то говорит под руку (вы не представляете, как трудно заставить окружающих заткнуться на пять секунд!) или просто шумит вода — звенит посуда — сверлит сосед…

Но вот арбуз выбран и куплен. Вы принесли его домой, записали звук и разрезали. Теперь вы готовы дать оценку его вкусовым качествам. Выбираем вкладку Save.

На этой вкладке мы видим два комбобокса для выставления оценок — сладость и спелость (sweetness and ripeness, работа над переводом ведется). Выставили оценку — нажали Save.

Внимание! Save можно нажать лишь раз. Так что, сначала выставьте оценку. По нажатию кнопки, звуковой файл переименовывается, и теперь он не будет стерт при следующей записи.

image

3. Наконец, записав (и значит, съев) с десяток арбузов, вы вернулись с дачи, где у вас не было Интернета. Теперь Интернет есть. Открываем вкладку Submit и нажимаем кнопку. Пакет (с десятком арбузов) уходит на сервер разработчика.

image

Написание серверной программы


Тут все просто, так что я лучше выложу полный код этого скрипта. Программа «ловит» файлы, дает им уникальные имена и складывает в директории, доступной только владельцу сайта.
<?php

        if (is_uploaded_file($_FILES['file']['tmp_name'])) 
        {
                $uploads_dir = './melonaire/';
                $tmp_name = $_FILES['file']['tmp_name'];
                $pic_name = $_FILES['file']['name'];
                
                $filename = md5(date('Y-m-d H:i:s:u'));
                
                move_uploaded_file($tmp_name, $uploads_dir.$filename);
        }
        else
        {
                echo "File not uploaded successfully.";
        }

?>


Обучение нейросети


Данные делятся на обучающие и тестовые, 70 и 30 процентов, соответственно. Нейросеть — сходится. Здесь нет никаких неожиданностей, однако, для новичков: не забудьте нормировать входные данные, это съэкономит вам массу нервов. Что-то в таком роде:
for file_name in os.listdir(path):
        nSweetness, nRipeness, arr_loaded = loadData(file_name)
        arr_data.append(arr_loaded / max(abs(arr_loaded)))
        # 2 stands for num. of inputs of a combo box - 1
        arr_labels.append([nSweetness / 2.0, nRipeness / 2.0])


Портирование нейросети


Есть несколько способов портировать сеть из питоновского окружения в Java. В последнее время, Гугл сделал этот процесс удобнее, так что, будете читать учебники — убедитесь, что они не устарели. Вот как это делал я:
from keras.models import Model
from keras.models import load_model
from keras.layers import *
import os
import sys

import tensorflow as tf

# -------------------

def print_graph_nodes(filename):
    g = tf.GraphDef()
    g.ParseFromString(open(filename, 'rb').read())
    print()
    print(filename)
    print("=======================INPUT=========================")
    print([n for n in g.node if n.name.find('input') != -1])
    print("=======================OUTPUT========================")
    print([n for n in g.node if n.name.find('output') != -1])
    print("===================KERAS_LEARNING=====================")
    print([n for n in g.node if n.name.find('keras_learning_phase') != -1])
    print("======================================================")
    print()

# -------------------

def get_script_path():
    return os.path.dirname(os.path.realpath(sys.argv[0]))

# -------------------

def keras_to_tensorflow(keras_model, output_dir, 
        model_name,out_prefix="output_", log_tensorboard=True):

    if os.path.exists(output_dir) == False:
        os.mkdir(output_dir)

    out_nodes = []

    for i in range(len(keras_model.outputs)):
        out_nodes.append(out_prefix + str(i + 1))
        tf.identity(keras_model.output[i], out_prefix + str(i + 1))

    sess = K.get_session()

    from tensorflow.python.framework import graph_util, graph_io

    init_graph = sess.graph.as_graph_def()

    main_graph = graph_util.convert_variables_to_constants(sess, init_graph, out_nodes)

    graph_io.write_graph(main_graph, output_dir, name=model_name, as_text=False)

    if log_tensorboard:
        from tensorflow.python.tools import import_pb_to_tensorboard

        import_pb_to_tensorboard.import_to_tensorboard(
            os.path.join(output_dir, model_name),
            output_dir)

model = load_model(get_script_path() + "/models/model.h5")
#keras_to_tensorflow(model, output_dir=get_script_path() + "/models/model.h5",
#       model_name=get_script_path() + "/models/converted.pb")

print_graph_nodes(get_script_path() + "/models/converted.pb")



Обратите внимание на последнюю строку: в Java коде вам нужно будет указать имена ввода и вывода сети. Этот «print» как раз их и печатает.

Итак, кладем в директорию assets проекта в Андроид Студио полученный файл concerted.pb, подключаем (см. здесь, или здесь, а лучше, здесь) библиотеку tensorflowinferenceinterface, и всё.

Всё. Когда я делал это впервые, я ожидал, что будет трудно, но… заработало с первой попытки.

Вот как выглядит вызов нейросети из Java кода:

        protected Void doInBackground(Void... params)
        {
            try
            {
                //Pass input into the tensorflow
                tf.feed(INPUT_NAME, m_arrInput, 1, // batch ?
                        m_arrInput.length, 1); // channels ?

                //compute predictions
                tf.run(new String[]{OUTPUT_NAME});

                //copy the output into the PREDICTIONS array
                tf.fetch(OUTPUT_NAME, m_arrPrediction);
            } catch (Exception e)
            {
                e.getMessage();
            }
            return null;
        }


Здесь m_arrInput — массив с двумя элементами, содержащий — та-да! — наше предсказание, нормированное от нуля до единицы.

Заключение


Здесь, вроде, полагается поблагодарить за внимание, и выразить надежду, что было интересно. Вместо этого, замечу, что на Гугле лежит первая версия программы. Вторая полностью готова, но данных — мало. Так что, если вы любите арбузы — поставьте, пожалуйста, прогу на ваш Андроид. Чем больше данных вы пришлете, тем лучше будет работать вторая версия…

Разумеется, она будет бесплатной.

Удачи, и да: спасибо за внимание. Надеюсь, было интересно.

Let's block ads! (Why?)

Франция требует сделать «право на забвение» глобальным — на что это может повлиять

Французская организация CNIL, занимающаяся вопросами защиты персональных данных в стране, потребовала от Google распространить «право на забвение» на весь мир. Регулятор желает, чтобы ссылки, удаленные из французской версии, скрывались и в версиях Google для других стран.

ИТ-гигант не согласился с этим требованием, потому спор Google и CNIL перешел в зал Суда Европейского союза. Далее разбираемся в сути конфликта.


/ фото Mounirzok CC

Что такое право на забвение


Право на забвение действует на территории Евросоюза с 2014 года. Граждане ЕС могут отправить в Google запрос с требованием скрыть конкретную информацию из поисковой выдачи. Закон позволяет скрывать неполные, неактуальные или заведомо ложные данные о человеке.

Вступивший в мае этого года в силу GDPR расширил понимание права на забвение. Теперь граждане ЕС могут запросить удалить ссылки из поисковой выдачи, если:

  • они возражают против их обработки;
  • эта информация получена без их согласия;
  • разрешение на обработку персональных данных было отозвано.

Прецедентом для принятия права на забвение стало судебное разбирательство в 2009 году, когда некий Марио Гонсалес (Mario González) обнаружил, что поисковик Google на запрос по его имени выдает судебные извещения двадцатилетней давности, опубликованные испанской газетой. Разбирательство длилось пять лет, но потом суд все же встал на сторону Гонсалеса.

Google каждый запрос рассматривает индивидуально. Всего в период с 2014 (с момента принятия закона) по 2017 год компания получила 2,5 миллиона запросов на удаление информации, причем 89% заявлений поступило от частных лиц, а не от публичных персон.

Разбирательство между Google и CNIL


В 2016 году CNIL потребовала от Google удалять ссылки по закону о праве на забвение не только для европейских версий поисковика, но и для всего мира. В качестве полумеры ИТ-гигант предложил скрывать ссылки во всех доменах при поиске с французских IP-адресов.

CNIL это решение показалось недостаточным: национальная комиссия обязала Google удалять результаты поиска и для стран за пределами Евросоюза. Американская компания не согласилась с этим требованием и получила штраф в размере 100 тысяч евро.

После этого Google подала иск против CNIL в Государственный совет Франции. Совет затруднился дать ответ по делу, так как оно касается международного европейского закона. Поэтому иск перешел в высший судебный орган ЕС — Суд Европейского союза.

Заседание прошло — 11 сентября. Ожидается, что решение вынесут в начале 2019 года.


/ фото Katarina Dzurekova CC

Мнения и аргументы сторон


Точка зрения CNIL

CNIL настаивает, что её претензии к Google нельзя считать попыткой применить французские законы за пределами страны. Представители организации говорят, что всего лишь требуют «соблюдения европейских законов неевропейскими компаниями, предлагающими свои сервисы в ЕС».

В CNIL отмечают, что для «полноценного» исполнения права на забвения необходимо удалять данные из результатов выдачи для всех стран. В противном случае граждане ЕС все равно смогут получить к ним доступ, если воспользуются VPN-сервисами.

Точка зрения Google

Компания считает, что европейские регуляторы не должны определять «внешний вид» и содержимое сайтов для пользователей по всему миру. ИТ-гиганта в этом деле поддерживает и правозащитная организация Article 19, которая занимается вопросами свободного доступа к информации.

Бывший главный юрисконсульт Google Дафна Келлер (Daphne Keller) говорит, что это дело может стать поводом для правительств других стран влиять на контент интернет-платформ для всего мира. Если прецедент будет зафиксирован, то неизвестно сколько времени пройдёт, прежде чем с подобными требованиями выступят другие государства. Потенциально такой подход может негативно отразиться на свободе слова в Сети.

С этим мнением согласился и Комитет репортеров за свободу прессы (RCFP). Организация отметила, что подобное применение концепции права на забвение противоречит международному законодательству и нарушает свободы людей.

Вероятный исход


Как мы уже говорили, окончательное решение суда будет известно только через несколько месяцев. Но Дафна Келлер сказала, что вероятность проигрыша Google довольно высока. Ранее юрист участвовала в деле поисковика против канадской компании, которая требовала от Google удалить ссылки на конфиденциальную информацию о её деятельности для всех версий сайта.

Канадский суд постановил, что ИТ-гигант обязан скрыть необходимую информацию из выдачи. И хотя позже это дело рассматривали в суде США, который принял противоположное решение, оно никак не отразилось на первоначальном постановлении. Дафна считает, что в кейсе CNIL может произойти аналогичная ситуация.

Пока неясно, что будет делать Google при поражении в суде. Когда в Wall Street Journal попытались получить у представителей компании какой-либо комментарий, они отказались распространяться на эту тему. Вполне вероятно, решение в пользу CNIL изменит механизмы взаимодействия регуляторов стран с онлайн-сервисами и отразится на «количестве» контента, представленного в интернете.



P.S. Дополнительное чтение в нашем блоге об IaaS:
P.P.S. Посты по теме в нашем блоге на Хабре:

Let's block ads! (Why?)

Профессиональные навыки, востребованные среди UX-специалистов (срез 2018)

С 29 августа по 07 сентября 2018 сообщество UX SPb (независимое сообщество UX-специалистов Санкт-Петербурга) проводило опрос, направленный на изучение профессиональных навыков специалистов по пользовательским интерфейсам. Сообщество обещало опубликовать результаты. Обещание исполнено :)

image

Опрос проводился в тематических группах UX SPb и UXClub в социальных сетях VK и Facebook. В исследовании приняли участие 109 респондентов. Для начала несколько слов о методологии исследования. После — о результатах.

Цель опроса


Целью опроса являлось получение «среза навыков» специалистов UX-индустрии, причем не в аспекте востребованности среди работодателей (такие данные несложно получить, полистав HH), а с точки зрения самих практикующих профи — какими навыками они стараются обзавестись, что планируют изучать, какие скилы считают своими сильными сторонами.

Зачем нужны эти данные и зачем они публикуются? В профессиональном сообществе проводится множество мероприятий разной тематики и уровня. мы надеемся, что собранные сведения помогут организаторам проводить еще более познавательные и привлекательные для коллег митапы, конференции, встречи.

Метод исследования


Для данного исследования был выбран метод удаленного немодерируемого опроса. Причина выбора очень проста — для получения максимально полных данных необходимо было привлечь максимально большое количество респондентов, а сделать это при очном интервью (путь даже по видеосвязи, а не личном) и доступных ресурсах было бы невозможно.

Данное исследование является достаточно простым с технической точки зрения, не подразумевает, например, исследования интерфейса, поэтому немодерируемый опрос подошел очень даже хорошо.

В качестве платформы для проведения опроса был выбран сервис Google Forms — бесплатный и простой в применении инструмент, обладающие необходимыми функциональными возможностями. Важно отметить, что Google Forms прост в применении не только для исследователя, но и для респондентов.

Форма опроса


В состав опроса были включены 6 групп вопросов, ориентированных на решение следующих задач:
  • Получение профессионального среза аудитории — род занятий и опыт работы;
  • Изучение навыков, которые активно осваиваются специалистами в данный момент;
  • Изучение навыков, которые стоят в планах на освоение;
  • Изучение навыков, которые специалисты считают своими сильными сторонами;
  • Обзор способов обмена профессиональными знаниями;
  • Сбор данных о месте проживания, возрасте и примерно зарплате специалистов.

Разумеется, все данные собирались строго анонимно. Респондентам не предлагалось сообщать свое имя, название компании или контактную информацию. «Сырые» данные не позволяют определить личности участников.

Принятые допущения, простота прохождения опроса


Прохождение опроса, даже такого короткого, может быть затруднительным или некомфортным для респондента (примем во внимание доступ с мобильных устройств, работу в транспорте, короткие перерывы на социальную сеть и кофе).

Поэтому при составлении анкеты предпочтение уделялось закрытым вопросам с ограниченным числом вариантов ответа. Некоторые вопросы предполагали выбора готового варианта или ввода произвольного ответа. Только два вопроса не содержали готовых вариантов, но предусматривали ввод коротких строк (названия одного-двух навыков, название города).

Для создания краткой анкеты некоторые вопросы были намеренно сделаны достаточно общими. Судя по отзывам нескольких респондентов, это создало определенные сложности с выбором. С другой стороны, это позволило получить пусть не детальную, но достаточно любопытную картину.

Также стоит отметить, что из всех респондентов только десятая часть воспользовалась возможностью для ввода произвольных значений вместо выбора предустановленного варианта. Это может говорить о том, что варианты были подобраны грамотно, а гипотеза о неготовности респондентов вводить текст верна.

Тем не менее, в анкете были допущены определенные промахи, о которых будет сказано ниже.

Оценка аудитории


Опрос проводится в течение 8 дней, за это время в профильных сообществах в социальных сетях VK и Facebook было сделано по две публикации. Суммарная аудитория, включая репосты, может быть оценена в 20'000 чел. (нужно учитывать, что далеко не все из них являются практикующими специалистами UX-индустрии).

В опросе приняло участие 109 респондентов. Распределение Роджерса позволяет распространить результаты на сообщество из приблизительно 2200 чел. (число активных участников, прошедших опрос, принимается за 5% его численности). Это сопоставимо с числом практикующих специалистов в Санкт-Петербурге с частичным захватом аудитории других городов и стран (также см. распределение по городам, ниже).

Полученные отзывы, касающиеся формы проведения опроса, позволяют предположить, что затруднились его пройти около 4% потенциальных респондентов (менее 1% от охваченной аудитории). Впрочем, коллеги, оставившие данные отзывы, сами предположили, что не являются его целевой аудиторией. Этому есть причина — по мере профессионального роста многие начинают осваивать смежные дисциплины или смещаются в сторону менеджмента. Частично данная гипотеза подтверждается произвольными ответами, данными отдельными участниками.

Самое интересное — результаты


Начнем с общего портрета аудитории — профессионального сообщества UX-специалистов.

Общий портрет аудитории


В опросе приняли участие специалисты из 22 городов. Наиболее активно участвовали коллеги из Минска, Киева, Москвы и Санкт-Петербурга (по возрастанию числа респондентов). Часть участников не сообщила место своего проживания — одно из ограничений принятого решения упростить заполнение анкеты.

На вопрос про возраст, как ни удивительно, аудитория отвечала намного более охотно. Возможно, дело в том, что возраст предлагалось задать, выбрав одно из предустановленных значений (с возможностью не сообщать ничего).

А вот так выглядит распределение аудитории по опыту работы в индустрии. Участникам предлагалось описать свою должность или род занятий (см. ниже), после чего отметить, сколько лет они занимаются соответствующей деятельностью.

Широко распространенное мнение о преобладании в молодой IT-индустрии новичков не подтверждается. По крайней мере, для UX-специалистов. Более половины респондентов работают в рамках профессии более 3 лет. Вполне заметный опыт.

Вот, к примеру, распределение по возрасту участников двух наиболее заметных групп (опыт работы 3–5 лет и более 5 лет, всего 59 респондентов).

Респондентам было предложено отметить, в компании какого типа они работают. предустановленные варианты ответа — «В продуктовой компании», «В агентстве/студии», «Я фрилансер», «Пока только учусь». Тут авторы исследование немного прокололись и не включили в число предустановленных значений такой логичный вариант как «В аутсорсинговой компании» (ведь крупный аутсорсер — это не продуктовая компания, но и не небольшая студия). К счастью, участники опроса воспользовались возможностью ввода своего варианта. Встречаются такие ответы, как «Университет» или «Банк» (респондент сомневался, можно ли отнести его к продуктовым компаниям). Для упрощения картины сотрудники аутсорсеров и продуктовых подразделений не-IT-компаний были включены в группу разработчиков продуктов, их рабочие процессы в большинстве случаев очень близки. Итоговое распределение по типу компаний выглядит так:

Оценить распределение специалистов по должностям было не так просто. Во-первых, каждый пишет даже сходные названия по-своему (по-русски, по-английски и так далее). Во-вторых, названия и смысловое содержание должностей часто бывает абстрактным или размытым. Поэтому названия были сгруппированы по внешней схожести и представлены здесь, в большей степени, как обзор названий должностей, но не решаемых респондентами должностных задач.

Итак, больше всего респондентов отрекомендовали себя как «UI/UX-дизайнеров» (21 человек), 20 человек используют аббревиатуру «UX» в сочетании со словами «дизайнер», «архитектор» или «проектировщик». 16 человек — аналитики и исследователи, 10 — представители руководящих должностей (менеджеры, арт-директоры). 8 респондентов называют себя «дизайнерами» (иногда с уточнением типа создаваемых продуктов). По 7 респондентов отнести себя к «проектировщикам» разных классов или «дизайнерам продуктов». 5 человек называют себя «менеджерами продуктов» или «владельцами продуктов». Остальные респонденты — в небольших количествах «web-дизайнеры», «дизайнеры-проектировщики» (необычно было встретить в таком опросе термин из архитектуры или промышленного дизайна), преподаватели, консультанты и дизайнеры смежных профессий.

Навыки специалистов


Основная цель данного исследования — получение сведений о профессиональных навыках, которые ценятся UX-специалистами. Они определяют «естественный» путь развития практикующего профессионала, его устремления или желания.

Респондентам было предложено ответить на три вопроса, связанных с навыками. Первый вопрос касался навыков, которые специалисты наиболее активно осваивают прямо сейчас. На выбор предлагалось четыре варианта ответа:

  • Владение популярными рабочими инструментами;
  • Рабочий процесс, внимание к деталям интерфейса;
  • Детализация абстрактно поставленных задач, поиск подходов к ее решению;
  • Владение аналитическими методами, поиск потребностей бизнеса.

Вопросы были намеренно сформулированы достаточно абстрактно, без упоминания конкретных инструментов или методологий. Ведь конкретные названия, особенно раскрученные на рынке, могли бы сбить респондента, подтолкнуть его к выбору модного ответа вместо близкого ему лично. Вот полученный результат:

Следующий вопрос, который был задан респондентам, намного более интересен с точки зрения исследователя, и намного более сложен с точки зрения обработки данных. Респондентам было предложено описать навыки, которые они бы перечислили в первых двух строчках своего резюме, готовя его в отправке в компанию своей мечты. Назначение данного вопроса в рамках исследования — попытаться понять, какие навыки, по мнению самих профессионалов, делают их профессионалами.

Ответы на данный вопрос подразумевали свободный ввод текста, поэтому ответы были представлены в самой разной форме. Тем не менее, авторам исследования удалось сгруппировать все навыки в шесть групп. Кто-то, описывая себя, как специалиста, делает упор на навыки менеджмента, кто-то — на владение конкретными методами или инструментами, некоторые красочно описывают свои навыки в аналитике. Есть среди респондентов исследователи пользователей, есть те, кто выше всего ценит сам факт наличия опыта или готовность быстро учиться. Наконец, некоторые респонденты выше всего ставят свои человеческие качества и навыки общения (aka soft-skills). Вот так выглядит полученная картина:

Любопытно, что такие навыки, как «графика» или «визуальный дизайн» в числе своих сильных сторон отметили буквально единицы респондентов.

Третьим вопросом из серии, посвященной навыкам, был вопрос про навыки, которые UX-специалисты хотели бы приобрести в следующие 2–3 года. Это, так сказать, навыки «на вырост». Как и в случае с вопросом про навыки, наиболее активно осваиваемые в данный момент, формулировки были намеренно выбраны достаточно абстрактными. Кроме того, в вопрос про построение рабочего процесса (см. ниже) была умышленно внесена определенная двусмысленность. Это описание может трактоваться как умение построить технологический процесс и как умение управлять командой. То есть, среди выбравших этот вариант присутствуют специалисты с интересами в области технологий и в области менеджмента. Примерная оценка соотношения — 50/50. Итоговое распределение:

Все специалисты работают в рамках разных компаний, используют разные инструменты, методы и процессы, имеют разные профессиональные интересы. Задавая вопросы и называя при этом названия продуктов или методик, авторы получили бы сведения о популярности продукта, но не об общей профессиональной направленности аудитории.

Пути обмена знаниями


Следующий блок вопросов анкеты был посвящен путям обмена знаниями между специалистами.
На рисунке вы можете видеть распределение по популярности методов, которыми коллеги предпочитают получать новые профессиональные знания. Интересно, что выступления известных практикующих профи несколько менее популярны, чем вообще любые выступления на конференциях. Респонденты имели возможность выбрать несколько вариантов ответа, отметить, что ни один из вариантов не подходит или ввести свой ответ. При этом единственный предложенный респондентом вариант относился, в большей степени, к академическим статьям. Затруднились сделать выбор всего два человека.

А вот на вопрос про то, как коллеги предпочитают делиться своими знаниями, ответить было сложнее — 34.9% респондентов затруднились с ответом. Зато была предложена масса альтернативных вариантов, самые популярные из которых — внутреннее обучение в рамках компании, выступление на конференциях, консалтинг. Итоговое распределение представлено ниже. Красным цветом выделены сгруппированные по близким темам ответы, предложенные самими респондентами.

Зарплаты UX-специалистов


В завершение опроса респондентам было предложено отметить приблизительный размер суммы, которую они получают в месяц за проекты, связанные с «UX». Чтобы было проще сравнивать размер дохода специалистов, живущих в разных странах, респондентов попросили отметить сумму, которая остается в их распоряжении после вычета всех налогов и перевести ее в российские рубли (нужно иметь в виду, покупательная способность при этом может быть все-таки самой разной). Примерно треть респондентов воспользовалась возможностью не отвечать на этот вопрос. Сведения, полученные от остальных, вы можете видеть ниже. Это распределение количества специалистов, получающих тот или иной доход, в зависимости от опыта работы по профессии:

Конечно, количество респондентов не так велико и их распределение по опыту работы неравномерно. Поэтому считать эти сведения исчерпывающими ни в коем случае нельзя. Однако, общее мнение составить можно.

На этом все. Спасибо за внимание!

P.S. Несколько заметок относительно самого исследования.
Можно с уверенностью утверждать, что в подобных экспресс-опросах, рассчитанных на максимальных охват аудитории, ввод любого текста приводит к росту числа отказов от участия. Аккуратно подобранные предустановленные значения позволяют существенно упростить заполнение анкеты. Однако, будет полезным оставить возможность и для нестандартного ответа на случай, если кто-то не может найти ничего подходящего. Выбор предустановленных значений нужно тщательно соотносить с задачами исследования и избегать использования раскрученных фраз, названий, брендов. Если, конечно, исследование не связано с ними напрямую.

В процессе исследования некоторые респонденты написали авторам про то, что они затрудняются выбрать вариант ответа и, возможно, не входят в целевую аудиторию опроса. Общие результаты позволяют предполагать, что данная гипотеза подтверждается, и уважаемые коллеги действительно в большей степени работают или стремятся работать в смежных дисциплинах. Например, в графическом дизайне, менеджменте или консалтинге.

Авторы надеются, что описание метода самого по себе тоже кого-то заинтересовало :)

Let's block ads! (Why?)

[Из песочницы] WiX.Py: cобираем MSI пакет «в три строчки»

Нет времени и желания изучать километровые файлы WiX, чтобы собрать MSI инсталлер для своего проекта, погружаясь при этом в бездны MSDN? Хотите собирать инсталлер, описывая его простыми и понятными терминами, в несколько строк? Есть клиническая склонность к кроссплатформенности и сборкам под Linux & Docker? Ну тогда вам под кат!


Разработчики поневоле

Собственно говоря, именно с этими "хотелками" наш проект кросс-платформенного редактора векторной графики и столкнулся пару месяцев назад.

Мы знали про WiX Toolset (Windows Installer XML), но даже беглый просмотр туториалов на официальном сайте навевал грусть и уныние — без серьезного погружения в XML описания инсталляторов не обойтись. Использовали более простой MakeMsi, но в нем была масса недоработок. И опять же, все эти инструменты не годились для сборки MSI под Linux.

Поиски привели к проекту wixl, который собирал MSI в Linux, но страдал серьезной недоработкой по функционалу и требовал те же XML файлы чудовищных размеров, что и WiX.

В результате, чтобы обзавестись нужным инструментом для сборки, мы переимплементили логику wixl на python, исправив многие недочеты и добавив необходимый функционал, и сделали проект кроссплатформенным. Так и появился WIX.Py — сборщик MSI с весьма низким порогом вхождения.


Как WiX.Py работает

Процесс создания MSI пакета упрощен до предела:


  1. В произвольной папке (напр. build) формируем содержимое для инсталляции в том виде, в котором оно будет на целевом компьютере.


  2. Заполняем небольшой JSON-файл. Например:

    {
    "Name": "MyApp",
    "UpgradeCode": "3AC4B4FF-10C4-4B8F-81AD-BAC3238BF690",
    "Version": "0.1",
    "Manufacturer": "My Company",
    "Description": "MyApp 0.1 Installer",
    "Comments": "Licensed under GPLv3+",
    "Keywords": "wxs, xml, build",
    "Win64": true,
    "_CheckX64": true,
    "_AppIcon": "resources/myapp.ico",
    "_ProgramMenuFolder": "My Company",
    "_Shortcuts": [
        {"Name": "MyApp",
        "Description": "MyApplication",
        "Target": "myapp.exe",
        "AddOnDesktop": true,
        "OpenWith": [".xml", ".wxs", ".yml"]
        }
    ],
    "_SourceDir": "build/",
    "_InstallDir": "myapp-0.1",
    "_OutputName": "myapp-0.1_win64.msi",
    "_OutputDir": "./"
    }
    

  3. Генерируем MSI пакет командой:

    wix.py <имя_файла>.json
    

Да, это полностью рабочий пример MSI пакета, который проверит перед установкой, что Windows 64bit, установит приложение в Program Files, добавит приложение в программное меню и на рабочий стол, и привяжет указанные форматы файлов к устанавливаемому приложению. Никакой магии и шаманства с регистром.

Можно еще больше сократить пример до 5-6 строк, но тогда функционал инсталлятора будет ну совсем куцый.

Используя WiX.Py, cборку MSI можно проводить как в Windows, так и в Linux, в т.ч. в Docker-контейнерах. Поскольку базовая libmsi может быть собрана на многих других UNIX-системах (напр. macOS), формально WiX.Py можно и на них использовать, только практического смысла это не несет.

Описание различных нюансов вы можете найти в документации проекта.


Заключение

Если вам подходит WiX.Py для решения задач по созданию MSI пакетов, но не хватает какого-либо функционала, заходите на наш сайт https://wix.sk1project.net и создавайте запрос на расширение функционала. Тоже самое касается обнаруженных багов — сообщайте и мы будем с ними бороться. Там же на сайте найдете исходный код и готовые пакеты для разных платформ.

Если присутствует желание сравнить с WiX, то на Хабре уже не раз были статьи, посвященные WiX: 1, 2, 3, 4.

Let's block ads! (Why?)

От антикварного радио до DIY-колонок: 12 каналов на YouTube про устройство акустики

Сегодня мы подготовили подборку YouTube-каналов, авторы которых рассказывают об устройстве винтажного и современного аудиооборудования: от настройки виниловых проигрывателей до сборки акустических систем. Всех, кому это интересно, приглашаем к просмотру под кат.


Фото Nathan Duprey / CC


Канал посвящен сборке акустических колонок своими руками и подойдет начинающим любителям DIY-аудио. Автор — Джаред Кирби (Jared Kirby), разрабатывающий наборы для сборки аудиооборудования — подробно рассказывает о выборе материалов и необходимых инструментах, показывает процесс сбора колонок и дает советы о том, как избежать распространенных ошибок. Иногда на канале появляются и обзоры на аудиотехнику. Например, в одном из видео Джаред разобрал умную колонку Amazon Echo II и показал, что там внутри.

Канал про аналоговый звук и Hi-Fi-оборудование. Автор дает советы о выборе виниловых проигрывателей, настройке и уходе за ними. На канале есть информация для желающих модифицировать свою аудиосистему и даже выпуски о создании кабелей своими руками.

При этом автор публикует материалы не только о домашнем музыкальном оборудовании. У него есть ролики, в которых он объясняет, как добиться наилучшего звучания от переносных аудиоустройств: кассетных и цифровых плееров, а также смартфона.



Пол МакГоуэн (Paul McGowan) — эксперт с 40-летним опытом в создании Hi-Fi-аудиокомпонентов, а также CEO и сооснователь PS Audio. YouTube-канал Пола выступает в качестве дополнения к его блогу на сайте PS Audio. В видео он отвечает на вопросы читателей об аудиооборудовании, форматах звукозаписи и обсуждает проблему поддельных Hi-Fi-компонентов. Ряд роликов посвящен созданию помещения для прослушивания музыки.




Чаще всего выпуски влога ведет основатель онлайн-издания Audioholics Джин Делласала (Gene DellaSala). Он делает обзоры на «железо» и проводит интервью с экспертами в области Hi-Fi-звука. В своих видеообзорах Делласала не описывает качество звучания аппаратуры и субъективные ощущения, а рассматривает конкретные показания тестовых приборов. Здесь вы найдете глубокий анализ технических характеристик устройств с объяснением, зачем они нужны и что обозначают.

Автор канала Ник Уилбур (Nick Wilbur) создает аудиооборудование своими руками и учит этому зрителей. Он публикует процесс создания колонок и сабвуферов. Некоторые ролики касаются вопросов электротехники, например, в одном из видео он рассказывает, как сделать кроссовер для акустики. У Ника есть свой сайт с дополнительной информацией, бесплатными схемами DIY-проектов из видео, а также ссылками на статьи с теоретической информацией.

Большая часть видео Джона Джини (John Geaney) посвящена ремонту оборудования: магнитофонов или антикварных приемников. Также Джон делится опытом по настройке и установке виниловых проигрывателей. Время от времени на канале появляются и видео с DIY-проектами.




Автор канала говорит о «внутреннем» мире акустической аппаратуры — микросхемах и радиокомпонентах — и объясняет принципы их работы. В частности, на JohnAudioTech есть ролик, посвящённый качеству транзисторов, а также закону Ома. Часто на канале появляются видео с обзорами на аудиоустройства — усилители или колонки.

Небольшой канал, на котором выходят видео о ремонте аудиооборудования. Автор показывает, как можно разобраться с различными неисправностями в приемниках и магнитофонах. На некоторые модели аппаратов он также снимает обзоры, как в случае с Toshiba RT-200. Темы видео не ограничены ремонтом аудио. Иногда автор публикует ролики с советами: как почистить контакты электронных компонентов, подключить мобильный телефон к магнитофону и др.

Канал инженера Пола Карлсона (Paul Carlson), цель которого, по словам автора, — сделать электронику проще и интереснее. Пол занимается ремонтом и модификацией винтажного оборудования: зачастую это радиоприемники 1930-х или 1940-х годов.

Важное место на канале Mr Carlson’s Lab занимают обучающие видео. В них Пол рассказывает, как работают диоды и радиолампы или как выбрать подходящий конденсатор. Для желающих поддержать развитие проекта автор запустил видеокурс на Patreon, в котором он делится своими навыками ремонта электроники.




Специализация автора канала — ремонт винтажных усилителей, и им посвящена большая часть видео. «Дядя Даг» не только восстанавливает аппаратуру, но и показывает, как создать усилитель из разных «ненужных» деталей. На канале много теории об аудиооборудовании: серии видео о резисторах, конденсаторах или использовании осциллографа для диагностики проблем в электрических цепях. Иногда на канале встречаются видео с обзорами на винтажную аудиотехнику. В частности, он рассказывал о редком гитарном процессоре Super Organ Tone родом из 1960-х и показывал джукбоксы1939 и 1948 года выпуска.




Марк Уокер (Mark Walker) более 30 лет занимается ремонтом и восстановлением аудиооборудования. Blueglow Electronics — это название его небольшой мастерской по обслуживанию винтажной аудиотехники. Чаще всего он работает с ламповым оборудованием и виниловыми проигрывателями. На своем канале Марк демонстрирует процессы ремонта «железа» и даёт зрителям советы, как правильно ухаживать за винтажной техникой. Иногда на канале Марка выходят обучающие видео, например, серия роликов о том, как читать схемы ламповых усилителей.

У нас тоже есть свой канал на YouTube, где мы рассказываем о технологических новинках в мире Hi-Fi и даем рекомендации по настройке и подключению акустических систем.

Больше интересного об акустике — в нашем Telegram-канале:

Кино на пластинках
Необычная портативка
Гид по встраиваемой акустике
Комфортный звук дома
Как зазвучали Звездные войны
Звуки из мира кошмаров

Let's block ads! (Why?)

К 2024 году в РФ появится сотовая сеть для чиновников и силовиков

image

О программе «Цифровая экономика» на Хабре уже неоднократно писали. Как оказалось, в ее паспорте указано, что к 2024 году в РФ должна быть создана сеть беспроводной связи для общественно значимых объектов и спецпотребителей. В первую очередь, это чиновники и представители силовых служб.

Сеть будет работать по технологии LTE-450, о чем сообщают «Ведомости». Особенность технологии — возможность управлять приоритетами для разных групп пользователей. Кроме того, абонентские устройства в этом диапазоне могут работать как в режиме рации, так и режиме передачи видеопотока. Особенности сети этого стандарта — высокие скорости и малые задержки передачи данных.
Оператором сети, скорее всего, станет Tele2, поскольку частотный диапазон 450 МГц, который нужен для работы сети, сейчас используется «Т2 РТК холдингом». К слову, монетизировать диапазон не удалось, именно поэтому появилась идея предоставить его для спецпотребителей. Последние получат возможность работать в собственной сети при помощи специальных абонентских устройств — смартфонов со специальными приложениями, которые предназначены для выполнения ведомственных задач.

К сожалению, условия и бюджет, требуемый для создания специальной LTE-сети в паспорте «Цифровой экономики» не приводятся. Но специалисты подсчитали, что общая ее стоимость может составить около 73,4 млрд рублей. Именно такая сумма следует из расчетов одного из профильных ведомств.

Что касается частотного диапазона, то он достался Tele2 вместе с компанией «Скай Линк» и некоторыми другими сотовыми активами «Ростелекома» в 2014 году. Оператор собирается принять участие в проекте, обсуждая такую возможность с профильными ведомствами. У Tele2 есть опыт оказания услуг в необходимом диапазоне. Так, оператор вместе с ДИТ обеспечивал связью экстренные службы на чемпионате мира по футболу — 2018.

Если Tele2 не станет основным исполнителем новой программы, государству придется изъять у него часть диапазона, во всяком случае так считает гендиректор «ТМТ консалтинга» Константин Анкилов. По мнению некоторых экспертов, создать современную сеть для работы в столь узкой полосе частот нельзя, в противном случае LTE-450 была бы востребована рынком. Ну а разворачивать сеть подвижной связи для спецпользователей, по мнению тех же экспертов — это неэффективное расходование бюджетных средств.

Let's block ads! (Why?)

[Из песочницы] Машинка на Arduino, управляемая с Android по Bluetooth, — полный цикл

Введение


Подробная история того, как из трех двигателей была собрана машина на Arduino, управляемая с Android-устройства по Bluetooth. За несколько десятков абзацев постараюсь максимально пошагово изложить, куда подключить каждый из проводов, как написать фирменное приложение и на каких детских граблях пришлось попрыгать больше недели.

Немного об уровне, авторе и предостережения


Я, автор, пацан 16-17 лет с одной из деревень Подмосковья, специализируюсь на написании android-приложений (а там сложнее что-то сжечь), поэтому ответственность за оптимальный подход к решению задач с себя снимаю.

Практически каждый из нижеописанных этапов занимал у меня больше, чем стоило бы, времени. Наверно, именно по этой причине хочу поделиться опытом. И при этом буду очень рад, если поругаете за ошибки и подскажите за оптимизацию.

Задача


Задача легчайшая – заставить ездить машинку, управляемую Arduino, а пульт заменить андроидом. Но в большинстве моментов пришлось изобретать колесо, потому что в интернетах подходящего решения найдено не было.

Понадобится


  1. Arduino
  2. Motor Shield (в моем случае две)
  3. Bluetooth
  4. Android
  5. Провода обычные

Основа конструкции


За основу была взята машина Lego Outdoor Challenger (в реальности выглядит менее пафосно). Все, что от нее осталось: корпус (все элементы украшения сняты) и три двигателя.
image
У машинки была своя плата, но одна из задач подразумевала универсальность: это сделал я, это смогут повторить другие. Мозги вынул, поставил Arduino Uno.

Установка Arduino


Создатели почему-то не предусмотрели места для Arduino, потому крепил на шурупы, просверлив пластик. Под плату подложил фанеру, чтобы ничего не закоротило. Под шурупы лучше подсунуть что-то пластиковое (кусочек бутылки), ибо плата от железный болтов не защищена.

Поверх платы сразу поставил две motor shiled, так надо. Чтобы управлять второй, придется прокинуть один провод с любого digital порта на H1 (направление) и второй с пина с поддержкой шима (помечены знаком «~», обычно 10, 11) на E1 (скорость).

Определение угла поворота


За поворот машинки отвечает на удивление не сервопривод, а обычный двигатель. Встает проблема: хорошо бы было его не сжечь, ведь угол поворота ограничен, а крутиться двигатель может сколько угодно.

Вариант с методом тыка отпадает, так как при разном уровне батареи количество тока, подаваемое на двигатель, будет изменяться, что приведет к постоянно меняющемуся углу. Крутить до упора тоже нельзя, рано или поздно рассыплются шестеренки.

Решение проблемы: отслеживать угол через замыкание. На фото продемонстрирована небольшая штучка, которая крепится недалеко от поворотного механизма. На часть, которая крутится вместе с колесами влево/вправо двигателем, прикрепляется гребешок с железными контактами.

Принцип работы: к каждой линии припаивается провод (всего их четыре), нижний подключается к плюсу (он зажат гребешком всегда, см. картинку), остальные провода уходят на минус. Когда зубик гребешка попадает и на нижний ряд, и на, допустим, третий, происходит замыкание, ток течет, это замечает Arduino.

Благодаря различным комбинациям трех полос, можно определить до семи углов. Например, когда ток есть на всех линиях, колеса повернуты в крайнее правое положение, когда ток есть только на верхней, колеса повернуты максимально влево. В таблице предоставлены все варианты.

Подключение угла и код


Для каждого уровня был выбран свой цвет: нижний – зеленый, первый снизу – красный, второй – черный, третий – белый. На начальном этапе использовались breadboard и светодиоды для визуальной отладки.

Схема подключения показана на рисунке. Плюс тянем к зеленому, остальные протягиваем к минусу. Через резистор, установленный для устранения помех и отсутствия КЗ, подключаем провода к выходам A0-A2. Выбраны они просто из экономии остальных портов.

Код дан с комментариями. Подключаем пины и опрашиваем их через digitarRead(). Если напряжение есть, вернется значение true. Далее смотрим, если результат означает, что колеса в крайних положениях, запрещаем дальнейший поворот в эту сторону.

Небольшая хитрость: поскольку выходы на 5В и 3.3В понадобятся в будущем, можно поставить плюс на один из digital-пинов. Перед каждой проверкой угла выдавать ток через digitalWrite(whitePin), потом проверять угол и убирать ток.

int speedTurn = 180; //скорость поворота, от 0 до 255

//пины для определения поворота
int pinRed = A0;
int pinWhite = A1;
int pinBlack = A2;

int pinAngleStop = 12; //выводит ток на светодиод, если достигнут максимальный угол, нужен 
//только для отладки 

void setup() {
 //пины поворота на считывание
  pinMode(pinRed, INPUT);
  pinMode(pinBlack, INPUT);
  pinMode(pinWhite, INPUT);
//светодиод 
  pinMode(pinAngleStop, OUTPUT);
//пины драйвера двигателя, направление и скорость
  pinMode(angleDirection, OUTPUT);
  pinMode(angleSpeed, OUTPUT);

  Serial.begin(9600);
}
//функция вызывается из loop(), когда приходит команда с андроида
void turn(int angle) {
  digitalWrite(pinAngleStop, HIGH); //выдаем ток на провод, подключенный к плюсу
  delay(5); //немного ждем, чтобы ток "успел" дойти
  
  if(angle > 149) {
        if( digitalRead(pinWhite) == HIGH && digitalRead(pinBlack) == LOW && digitalRead(pinBlack) == LOW) { 
          //если достигнуто крайне правое положение, выйти из функции не подавая ток, чтобы не 
          //сжечь мотор
          return;
        }
        //если угол не максимальный, поворачиваем
        digitalWrite(angleDirection, HIGH);
        analogWrite(angleSpeed, speedTurn);
  } else if (angle < 31) { 
        if(digitalRead(pinRed) == HIGH && digitalRead(pinBlack) == HIGH && digitalRead(pinWhite) == HIGH) {
          //если достигнуто крайне левого положение, выйти из функции не подавая ток, чтобы не 
          //сжечь мотор
          return;
        }
        //если угол не максимальный, поворачиваем
        digitalWrite(angleDirection, LOW);
        analogWrite(angleSpeed, speedTurn);
  }
  digitalWrite(pinAngleStop, LOW); //убираем ток с определителя угла
  delay(5);
}


Распараллеливание ходовых колес


Изначально два ходовых двигателя соединены вместе. Их рассоединил по двум причинам: поворот эффективней, если колеса крутятся в разные стороны, и два мощных двигателя одна плата не вытянет.

Проблема: у motor shield два выхода, каждый из которых выдает до 2 ампер. Каждый двигатель ест по 0,7А. Вроде меньше, но не при максимальных нагрузках. Допустим, машинка застряла в песке или уперлась, ток возрастает выше ампера. Не критично, но потенциально опасно.

А вот критичным оказалось то, что плата греется. Через минуты полторы после заезда, motor shield нагревалась и начинала работать безобразно: токи подаются не те, колеса не крутятся и прочее.

Решение обоих проблем: один двигатель подключил к одной motor shield, второй – к другой. Как ни странно, помогло. Температура упала, перегрев отсутствует. Можно было поставить радиатор, но крепить тяжело.

Подключение Bluetooth


Я использовал модель HC-05, что сыграло роковую шутку. Подключаются все блютузы одинаково: один провод на 3.3В (иногда начинал работать только от 5В), второй на минус, еще два на порт 0 и 1 (чтение и отправка соответственно). Провод, подписанный RXD на bluetooth, втыкается в TXD ардуино, а TXD в RXD (если перепутаете, то данных не увидите).

Есть оговорка: порты 0 и 1 по умолчанию используются Serial, через который заливает скетч. То есть, пока воткнут блютуз, скетч не зальется. Есть два выхода: вынимать блютуз на время заливки или переназначить входы и выходы блютуза. Второй вариант осуществляется двумя строчками

#include <SoftwareSerial.h> \\подключение библиотеки
SoftwareSerial BTSerial(8, 9); \\установка 8 и 9 пина заместо 0 и 1

Подводный камень, съевший у меня трое суток работы – скорость общения. По привычке установил 9600 и пошел пробовать. То данные не приходили, то была каша символов. И в конце концов ответ – модель HC-05 общается на 38400! Очень сильно обратите внимание на то, что в Setup() я выполню BTSerial.begin(39400), хотя Serial.begin(9600).

Система отправки команд


Статья становится слишком длинной, поэтому рассмотрение кода Arduino и Android вынесу в отдельную вторую часть, а сейчас опишу принцип.

На андроид устройстве есть джойстик (круг, о реализации которого также во второй части). Андроид считывает показания с него и конвертирует их в подходящие для ардуино числа: скорость из пикселей превращает в значение от -255 до 255 (отрицательные – задний ход), а также определяет угол. Я сознательно отдал эту задачу телефону, так как он куда мощнее и спокойно справится с подсчетом нескольких сотен значений в секунду.

После установки сокета данные отправляются в следующем формате: @скорость#*угол#. @ — говорит о том, что следующие цифры содержат скорость, # — извещает об окончании значения скорости, * — начало значения угла, # — закончить запись угла. Цикл бесконечен, команды отправляются каждые 100 миллисекунд (цифра подобрана оптимальная). Если ничего не нажато на андроиде, то ничего и не отправляется.

Алгоритм приема данных подробно описан в коде скетча. Он не раз переписывался и, как по мне, работает идеально.

Заключение первой части


В этой статье я попытался раскрыть все, что касается физической части машинки. Вероятнее всего, что-то упустил, так что обязательно спрашивайте.

Но самое интересное, как по мне, осталось на второе – программа Arduino и приложение на Android, там творится настоящая магия, по крайней мере, для молодого меня.

Если вы не найдете ответа на какую-то часть и захотите потыкать меня в недостатки лично, жду – dendolg1@mail.ru, .

Let's block ads! (Why?)

История переезда системного администратора в Германию. Часть вторая: переезд и первые шаги

Всем привет.

Я наконец-то изыскал время и написал вторую часть своей истории об IT-эмиграции. Первую часть можно прочитать тут — История переезда системного администратора в Германию. Часть первая: поиск работы и виза. В этой части я опишу подробно, как мы с сестрой обустраивались на новом месте, какие ошибки при этом допускали и сколько нам эти ошибки стоили.

Итак, поехали.

У нас было два загранпаспорта, национальная виза, контракт на работу, договор на учебу и целое множество вещей всех сортов и расцветок, а также лысый кот, длинный список дел, норовящая развалиться машина и несколько тысяч евро. Не то чтобы всё это было так уж необходимо для переезда в Германию, но если уж начал эмигрировать из России, то становится трудно остановиться. Единственное, что вызывало у меня опасение — это жилье. Ничто в мире не бывает более беспомощным, безответственным и порочным, чем поиск квартиры во Франкфурте. Я знал, что рано или поздно мы столкнемся и с этим.


Подготовка к переезду


Когда я наконец получил визу и стало понятно, что мы действительно едем, у нас с сестрой оставался всего месяц. До этого активные действия предпринимать было чревато — визу могли и не дать. В итоге нам пришлось крутиться, как белкам в колесе. Ехать мы решили на машине. Пришлось срочно делать коту международные ветеринарные документы, сортировать вещи на «взять с собой сейчас» и «отвезти пока к родителям», чинить машину, идти по врачам, ругаться с хозяевами нашей питерской квартиры по поводу залога… Сестре пришлось еще и совершить экспресс-забег по куче учреждений для сбора документов на языковую визу Германии. Работали мы оба почти до последнего дня, потому что отчаянно нуждались в деньгах — накопления у нас, конечно, были, но сколько уйдет на переезд, мы не могли прикинуть даже примерно. Тут нам очень сыграло на руку мое увлечение радиолюбительством: экстренно распродав почти весь накопившийся за без малого 9 лет радиохлам, удалось выручить очень неплохую сумму.

Вопрос жилья встал перед нами практически сразу. Найти в Германии что-то на долгий срок удаленно — нереально от слова «совсем». Тем более во Франкфурте. Тем более за месяц до приезда. И уж тем более с котом. Через сайт для поиска туристического жилья airbnb.com сестра нашла нам идеальный для этих условий вариант — сдающуюся посуточно квартиру в пригороде рядом с вокзалом, в 25 минутах на электричке от центра города. Стоило это каких-то совсем уж жутких денег, в районе 1300 евро за месяц, но выбирать нам было не из чего: все остальное было либо дорожа раза эдак в два, либо располагалось у черта на рогах.

Решив основные дела, мы проложили маршрут через Латвию, Литву и Польшу, рассчитали дорогу на 3 дня, забронировали две квартиры для ночевок, уволились и стали собирать вещи.

В последний день мы грузили в машину самое необходимое. Оба были к тому времени на ногах уже почти сутки. Вообще-то у нас был четко расписанный план переезда, и никакого аврала не предполагалось: все должно было быть погружено еще накануне, а в последний день мы хотели отмечать наш отъезд в пабе… Но меньше чем за неделю до назначенной даты выезда меня угораздило серьезно заболеть, и в итоге все планы полетели к чертям. А еще мы наивно планировали оставить на заднем сидении место для кота, где он мог бы лежать, спать и есть, но «самых необходимых» вещей набралось столько, что машина была забита по самую крышу (включая два багажника), а мы здорово прокачали скилл «впихнуть невпихуемое». Кот в итоге ехал всю дорогу у сестры на руках.

image

Было раннее утро, 22 сентября 2017 года. Мы в последний раз выходили из подъезда дома, в котором прожили целый год. На парковке стояла загруженная по самое некуда машина, в переноске мы несли кота, еще не подозревающего, какое испытание его ждет. Чувства у нас были сложные: прошлая жизнь закончилась, новая еще не началась, впереди было 2200 километров и три дня пути.

Началась наша дорога в Германию.

Переезд


Первый день я не забуду, наверное, никогда. Маршрут был, казалось бы, простой: Санкт-Петербург — Каунас. Но сначала мы потеряли много времени в консульстве на неудачную попытку одним днем получить визу для сестры (о готовности которой нам сообщили накануне, но для ее проставления консульство потребовало оставить у них паспорт на сутки), а потом собрали кучу пробок и битых три часа торчали на границе из-за кота, которого очень неспешно оформляла тетенька из ветеринарного контроля. В итоге в тот день я, еще не совсем поправившись и с жуткого недосыпа, провел за рулем около 15 часов, держась на жаропонижающих и энергатиках. Кот тоже героически держался, но на двенадцатом часу не выдержал и справил малую нужду, сидя у сестры на коленях… Пришлось срочно искать посреди ночи заправку, чтобы привести в порядок сестру и машину. Добравшись таки уже глубокой ночью до Каунаса, мы рухнули спать как убитые.

Второй день был проще. Заехав в магазин за местной симкой (куда же без интернетов-то), мы взяли курс на польский Лодзь. Три радиостанции в машине бухтели на разные голоса, кот вяло орал, мы с сестрой глазели по сторонам и все еще не верили, что едем не в отпуск. Хорошенько попетляв под Варшавой из-за строительства автобана и отрихтовав порог машины о некстати подвернувшийся булыжник, мы к вечеру добрались до Лодзя. Кот расслабился — похоже, подумал, что уж теперь-то его никуда больше не повезут… Бедолага.

В третий, финальный, день мы преодолели около 900 километров — к счастью, уже по автобану. Кот смирился и спал, спрятав голову у сестры на коленях. В городке Ной-Изенбург (Neu-Isenburg), что под Франкфуртом, нас встречал хозяин нашей временной квартиры, Адем. Турок по национальности, он прекрасно владел немецким, давно уже жил в Германии и оказался очень гостеприимным человеком — ждал до поздней ночи, «застолбил» для нас парковочное место и помог разгрузить машину. Прежде чем рухнуть спать, я еще успел достать из нашего багажа Juniper SRX100, подключить к нему точку доступа, модем и завести доступ в Сеть через LTE — в этой квартире подключения к Интернету не было. Сестра, тоже из последних сил, запостила в соц.сети, что мы доехали :)

Регистрация по месту жительства


Самое первое, что нужно сделать приехавшим в Германию не в качестве туриста — это зарегистрироваться по месту жительства. Без регистрации (Anmeldung) здесь нельзя сделать практически ничего — она требуется для открытия счета в банке, для заключения многих контрактов на услуги и, главное, для получения вида на жительство — Aufenthaltstitel. О том, что делать этот самый Anmeldung в снятом на месяц через airbnb жилье как-то не принято, мы узнали уже по приезду. Хозяин квартиры сначала отказал нам категорически, но потом все же согласился обсудить этот вопрос и пожаловал к нам в гости со всем семейством — видимо, для доходчивости. В чем же прикол, спросите вы?

Все достаточно просто. Если вы снимаете квартиру и зарегистрированы в ней, выселить вас можно только через суд. Даже если вы за нее не платите и всячески нарушаете общественный порядок. Такой геморрой никому из квартиросдатчиков, естественно, не нужен, но нам удалось убедить хозяев в нашей благонадежности и получить их письменное согласие на регистрацию — под честное слово, что злоупотреблять доверием мы не будем. С этой бумагой мы сходили в ратушу (Bürgeramt) и зарегистрировали меня, получив заветный Meldbescheinigung — подтверждение регистрации по месту жительства. Почему только меня? Как я уже рассказывал, сестра не успела получить немецкую языковую визу и приехала по туристической шенгенской, а туристов тут не регистрируют.

Банковский счет и Termin


Следующим квестом был банк, где нужно было открыть счет — без него жить в Германии невозможно. На этот счет приходит зарплата, с этого счета списываются разные платежи (телефон, интернет etc)… Взяв с собой сестру в качестве переводчика, я направился в ближайший к нам банк — это оказалась Sparkasse. И вот тут-то мы узнали волшебное немецкое слово Termin, которое во многом определяет жизнь немцев :) Termin — это запись в учреждение, или к врачу, или вообще любая назначенная встреча. Большинство действий в фирмах и учреждениях Германии делается только с предварительным назначением Termin. Банк не оказался исключением — на открытие счета нужно было назначить Termin, а ближайшее свободное время у них было только через неделю.

Усомнившись в адекватности банка, я позвонил своему работодателю — там меня заверили, что это в Германии норма, и что требовать с меня данные банковского счета в первый рабочий день никто не будет. Так что мы назначили Termin, и через неделю мне за полчаса открыли счет, на который мы со вздохом облегчения положили наши привезенные из России наличные сбережения. Сестре, опять-таки из-за «неправильной» визы, счета в банке пока не полагалось.

Тут я допустил первую ошибку: открыл счет в пригородном отделении банка, не убедившись, что смогу его обслуживать там, где собираюсь жить. Sparkasse — это как российский Сбербанк, куча филиалов под одним брендом, но обслуживать счет можно только там, где его открывали. Как выяснилось позже, во Франкфурте филиалов областной Sparkasse просто нет, как и cash-in банкоматов оной. Хорошо хоть снимать наличные можно без комиссии по всей Германии, да.

Мобильная связь и контракты


Мобильных операторов в Германии множество, однако все тарифы более-менее похожи и делятся на две группы — prepaid и контрактные, и по сравнению с Россией они очень дорогие. Средненький пакет (безлимитные звонки и 5-7 ГБ трафика в месяц) обойдется в 15-20 евро на prepaid тарифе. На контракте немного дешевле.

Чтобы временно решить проблему домашнего интернета, мы купили контрактный тариф с условно-безлимитным трафиком (10 ГБ LTE без ограничения скорости, дальше скорость режется до 1 МБит) за 29 евро в месяц. Пользовались мы этой симкой несколько месяцев — до тех пор, пока не переехали на постоянную квартиру и не подключили стационарный интернет, после чего «безлимитная» карта перешла к моей сестре, которой вечно не хватало 5 ГБ на ее prepaid тарифе. Мне же на работе сразу выдали телефон с корпоративной симкой.

Здесь есть один нюанс, которого часто не знают новички: контракт заключается на определенный срок (год или два), и разорвать его раньше невозможно. Просто перестать платить тоже нельзя — дело быстро дойдет до коллекторов и/или суда, плюс ваша кредитная история будет безнадежно испорчена. Более того, контракт продлевается автоматически, если вы за 3 месяца до его истечения не написали отказ от продления. То же самое касается вообще практически любых контрактов на услуги — интернет, абонемент в фитнес-клуб, подписки на журналы… Так что советую новичкам быть очень внимательными в этих вопросах.

Медицинская страховка


Жить в Германии без страховки нельзя, причем страховки немецкой — наши туристические годились только на первое время. Видов страховок здесь две: государственная и частная. Если не вдаваться в детали, то разница такова: государственная страховка покрывает меньше рисков (стоматологию почти совсем не покрывает) и ждать приема врача по ней дольше, зато она платит врачам напрямую, сам застрахованный ничего не оплачивает. В частной страховке больше плюшек, но купить ее могут не все, и механизм оплаты в ней странноватый: сначала оплачиваешь счета от врачей сам, а потом страховая компания возмещает потраченное.

Я имел возможность выбирать между этими двумя видами страховок и выбрал государственную. Возможно, потом и перейду в частную, но пока такой потребности не испытываю. Цена этой страховки не фиксирована, а считается как процент от зарплаты. Моя сестра, как неработающая языковая студентка, могла застраховаться только в частной страховке. Ценники там начинаются от 300 евро в месяц и выше, но есть специальные тарифы для школьников и студентов, которые стоят на порядок меньше — от 30 до 80 евро в месяц. Сестра долго сравнивала предложения разных страховых компаний в этом сегменте, и в итоге остановила свой выбор на страховке за 60 евро в месяц, покрывающей почти все, включая лекарства. Спустя примерно полгода ей пришлось обратиться к врачу, счет пришел по российским меркам космический — мы его оплатили и отправили в страховую вместе с чеками на лекарства, и нам возместили абсолютно все расходы до последнего цента.

Поиск постоянного жилья


В России мы привыкли, что снять квартиру — совершенно не проблема, были бы деньги. Предложение превышает спрос, можно без особых проблем выбрать жилье по своему вкусу и кошельку. Если что-то не нравится, всегда можно съехать. Хозяева квартиры, впрочем, тоже могут разорвать договор аренды и выселить арендатора, да. Полная свобода. Переезд стоит копейки. Залог при съеме жилья редко превышает месячную арендную плату.

В Германии же все с точностью до наоборот. В крупных городах желающих снять любое жилье раз в 10 больше, чем предложений. На хорошее жилье в приличном районе с нормальной инфраструктурой спрос и того вьше. Аренда стоит дорого, залог составляет в среднем 3 месчячных платы, так что денег нужно много и сразу. Если вы иностранцы, живущие тут без году неделя, вам будет сложно найти приличное жилье. Если вы еще и не муж-жена и не парочка, и вам не подходит вариант “одна спальня и огромная гостиная, она же кухня” — будет еще сложнее, поскольку примерно 50% квартир по планировке тут “заточены” именно под семейные пары. Имеете машину и хотите выделенное парковочное место/гараж — я вас поздравляю, сложность поиска увеличивается в два раза. Если у вас вдобавок еще и кот — можете сразу вешаться, а уж если при всем этом вы не очень хорошо владеете немецким языком… Ну вы поняли, да. Миссия почти невыполнима.

Тут я допустил вторую ошибку: не поддался на уговоры сестры сразу бронировать ту квартиру с airbnb на два-три месяца. Почему-то я был уверен, что уж за месяц-то мы обязательно что-нибудь найдем… Однако реальность оказалось сурова.

Здесь правят бал арендодатели. Жилье почти всегда снимается на годы, многие живут в съемных квартирах десятилетиями. Арендатор в Германии защищен многочисленными законами, и выселять его, даже если он пьянствует водку, нарушает безобразия и не платит за аренду — сложно, долго и без гарантии успеха. Получить такие проблемы на свою голову не хочется никому, поэтому к поиску жильцов арендодатели подходят со всей ответственностью.

Арендодатели придирчивы. Арендодатели подозрительны. Они будут с сомнением разглядывать ваш российский паспорт. Они будут въедливо выяснять, почему ваша виза действует только полгода — и вам придется долго доказывать, что вы приехали по программе Blaue Karte и визу вам поменяют на вид на жительство, но для этого нужна, черт возьми, квартира и регистрация. Они будут требовать копии вашего трудового договора, паспорта и визы, справку о трудоустройстве, справку о зарплате и о том, что у вас нет долгов. Они будут мрачно расспрашивать, как часто ваш кот дерет стены и гадит по углам, и морщиться, слушая ваши ответы на кривом немецком или средненьком английском. А после всего этого они будут выбирать — и с 90% вероятностью выберут не вас, потому что среди желающих наверняка найдется пара нормальных немецких немцев, с родным немецким языком, немецкими паспортами и без животных. В общем — время шло, квартира не находилась, и мы с сестрой стали нервно шутить про то, как с котом и вещами переедем жить под мост.

В конечном итоге, сестра совершила чудо и после почти месяца звонков, рассылки писем и поездок на просмотры нашла нам в черте города очень хорошую и относительно недорогую трехкомнатную квартиру, в зеленом районе и в двух шагах от метро. Определенная заслуга здесь есть и у кота — узнав, что он у нас лысый, маклер на том конце провода строго спросил, не мерзнет ли котик зимой. А при встрече умилился с фотографий, так что в этот раз нам не отказали.

Кстати, до недавнего времени, если квартира сдавалась через маклера, то его услуги оплачивал арендатор — а это еще плюс одна-две арендные платы. Но пару лет назад приняли закон, согласно которому маклера оплачивает тот, кто его нанял (в данном случае, арендодатель) — что несколько облегчило и без того непростое положение тех, кто ищет жилье в крупных городах.

В общем, квартира нашлась, но была одна незадача — освобождалась она только с декабря, а с арендованного через airbnb жилья нам надо было съехать уже в конце октября, продлить его было нельзя. Мне до сих пор жутко вспоминать, в какую астрономическую сумму нам обошлось временное жилье на этот период и насколько неудобным оно было.

Kaution


Важным моментом был также и залог за квартиру — Kaution. Он составляет три арендных платы без учета коммунальных услуг (это называется Kaltmiete), и в нашем случае требовалось внести более 2000 евро. Расставаться с такими деньгами не хотелось, и я нашел выход: можно заключить специальную страховку, которая называется Bürgschaft. Она стоит около 100 евро в год и гарантирует, что вашему арендодателю будет выплачена компенсация ущерба в размере до тех самых трех арендных плат, если вы в квартире что-то сломаете. Не все арендодатели согласны принять такую страховку вместо классического залога, но нам повезло.

Мебель


То, что квартиры на долгий срок здесь сдаются, как правило, без мебели, мы уже знали. В них часто даже нет кухни — просто голые стены плюс санузел. Поэтому мы заранее закладывали определенную сумму на то, чтобы квартиру обставить. С кухней повезло — мы ее относительно дешево выкупили у предыдущих жильцов вместе со всей техникой, а вот всю остальную мебель пришлось покупать, доставлять и собирать. Дешевле и проще всего оказалось это сделать в IKEA — мы выбрали мебель, и за не очень большую сумму (хотя и превышающую в несколько раз стоимость таких услуг в России) нам ее привезли и частично собрали (мы заказали сборку только габаритных вещей вроде шкафов и кроватей, все остальное собирали сами). Суммарно за всю мебель, включая кухню, мы заплатили около 3000 евро.

Интернет


Следующей проблемой стало подключение интернета. Ethernet или оптика в квартире здесь почти никогда не встречается, самые распространенные методы подключения — VDSL2 по телефонной линии, или DOCSIS3 через кабельное ТВ. У нас кабельных провайдеров не было, оставался только DSL, и вот с ним мы хлебнули горя. Интернет нам подключали два месяца. Потому что все телефонные линии здесь принадлежат монополисту — Deutsche Telekom, и при подключении к любому провайдеру требуется визит монтажника (Techniker) от них. А монтажник может просто не прийти в назначенное время, соврав потом, что вас не было дома. Ему за это ничего не будет, зарплата у него фиксированная и от пунктуальности не зависит. Поэтому монтажникам монополиста откровенно плевать на клиентов — без разницы, подключаетесь вы к Telekom напрямую или к их конкурентам.
Напдись гласит: «Монтажник Telekom, я дома. На самом деле! Как и в прошлые разы!»

К нам монтажник не пришел дважды, отговариваясь тем, что… «не смог найти дом». В третий раз я просто вышел с утра пораньше прогуляться во двор — и поймал нашего монтажника, который приехал и сидел в машине (явно намереваясь отбыть восвояси, даже не позвонив в дверь). После этого он с недовольной физиономией все же соизволил нас подключить (15 минут работы). Такая ситуация, к сожалению, типична для любого более-менее крупного города Германии. Правда, это единственное негативное впечатление о немецком интернете — свои 100 МБит эта VDSL линия выдает, и работает без нареканий.

Стоит наш тариф 30 евро в месяц — сюда входит 100 МБит/с линия, городской телефон по SIP и внешний IP.

Вид на жительство


Въездная виза дается посольством Германии, как правило, на срок от 3 до 6 месяцев. За это время нужно успеть найти жилье, зарегистрироваться и подать документы на Aufenthaltstitel — ВНЖ, выдачей которого ведает Ausländerbehörde — Ведомство по делам иностранцев. Оформляться ВНЖ может либо как вклейка в паспорт (старый вариант), либо как отдельная пластиковая карточка (новый вариант, сейчас почти всем делают именно так). Вклейка напоминает визу и делается на месте при подаче документов, а карточку нужно ждать около месяца. Выглядит она вот так:

Здесь мы с сестрой допустили третью ошибку: отложили решение вопроса с ВНЖ до времени, пока не найдем постоянную квартиру. Это выглядело разумно, потому что за Франкфурт и область отвечают разные Ausländerbehörde, и с областной регистрацией нас бы не приняли во Франкфурте. Поэтому мы стали выяснять этот вопрос лишь в декабре, когда переехали в новую квартиру и зарегистрировались в ней.

Как позже оказалось, областные Ausländerbehörde — маленькие филиалы рая, где нет очередей и работают милейшие люди, а во Франкфурте это огромное здание с дикими очередями и сотнями жутко занятых сотрудников, которые не отвечают на телефон и не читают электронную почту. С трудом добившись от них ответа, я выяснил, что ближайший Termin на подачу документов — аж в мае, притом что моя виза истекала в марте. Сестре, которая к тому времени уже успела слетать в Питер и вернуться с «правильной» визой, ведомство вообще не соизволило ответить.

В итоге нам пришлось провести увлекательную ночь перед дверями Ausländerbehörde — потому что тех, кто пришел без Termin, там принимали только по 10 человек в день, открывалось ведомство в 7:30 утра, и для попадания в десятку счастливчиков очередь нужно было занимать часов так за 4-5. Пройти нам удалось со второго раза. У меня без проблем приняли все документы на Blaue Karte, а вот сестру с ее учебной визой завернули — как оказалось, ей по почте высылали письмо со списком требуемых документов, только вот оно куда-то затерялось, а без этого списка, естественно, документы сестра принесла не все. Причем на словах сотрудники ведомства расписали тогда один порядок действий, а позже стали требовать совсем другое.

Это была четвертая ошибка: нужно всегда выяснять заранее и в деталях, какие документы требуются. Кроме того, при взаимодействии с Ausländerbehörde нужно фиксировать фамилию сотрудника и требовать письменное подтверждение его слов.

Очередь перед дверями франкфуртского Ausländerbehörde в 3 часа ночи.

Немного о миграционной бюрократии


Я получил свой Aufenthaltstitel примерно через месяц, а вот у сестры эта история затянулась с января аж по сентябрь: ответственная за студентов сотрудница ведомства ее за что-то невзлюбила, придиралась к каждой запятой в документах, требовала кучу взаимоисключающих бумажек, а в конце концов отказала в выдаче ВНЖ и пригрозила депортацией. Пришлось нанять адвоката, услуги которого обошлись в 500 евро — только после его вмешательства проблема наконец была решена, и сестра получила заветный вид на жительство. Придирчивую сотрудницу Ausländerbehörde, кстати, после жалобы адвоката выпихнули на пенсию.

Машина в Германии и таможня


Мы приехали сюда на моем стареньком Hyundai Accent. Растаможить его здесь было бы реально: действуют льготы для иммигрантов, но вот поставить на учет — увы. Машины российской сборки здесь требуют дорогостоящей экспертизы выбросов CO2, стоимость которой превышала стоимость самого автомобиля. Поэтому, до покупки новой машины, я катался на российских номерах.

Здесь есть один нюанс, который обычно мало известен иммигрантам: ввозить в Германию машину с иностранной регистрацией можно сроком на полгода, но только если вы приехали временно — к примеру, это командировка или работа по срочному контракту. Как только вы получаете долгосрочный вид на жительство — вы обязаны растаможить машину и поставить ее на учет, в противном случае пользование ею становится незаконным. Полиция временами останавливает на автобанах машины с иностранными номерами для проверки документов, и если вы предъявите долгосрочный ВНЖ — получите штраф, принудительную растаможку и, опционально, обвинение в уклонении от уплаты налогов. Также можно попасть под проверку патруля Zoll (таможни), которая тоже частенько интересуются иностранными авто. Если же попасть в ДТП — то страховка «Зеленая карта», вполне вероятно, может отказаться покрывать ущерб, потому что автомобиль находился в стране незаконно. Поэтому трижды подумайте, прежде чем пользоваться здесь иностранной машиной после получения ВНЖ — рано или поздно это выяснится, и заплатить придется немало.

Что дальше?


И вот снова утро, 22 сентября. Этот пост я пишу из нашей немецкой квартиры под ободряющие вопли кота. С того дня, как мы покинули Россию, прошел ровно год. Конечно, этого мало, чтобы стать в новой стране «своими», но мы уже вполне здесь обжились, наступили на все типичные для эмигрантов грабли, решили первоочередные бюрократические и не очень вопросы, и привыкли к немецкому укладу жизни.

В следующей, заключительной, части моего рассказа я опишу немецкий повседневный быт, различия менталитета и соотношения расходов и доходов, поговорю еще немного на автомобильную тематику и расскажу, как все у нас сложилось: у меня с работой, а у сестры с учебой.

Котик, обзаведшийся за этот год немецким паспортом (ветеринарным, но как звучит!), желает всем эмигрантам удачи :)

Полезные ссылки


Сайты, где мы искали квартиру:
www.immobilienscout24.de
www.wg-gesucht.de

Сайты с информацией, полезные начинающим эмигрантам:
toytowngermany.com — англоязычный сайт с активными обсуждениями многих тем, которые важно знать иммигранту-новичку или тому, кто только собирается переехать в Германию. Народ там большей частью адекватный и говорит дело,
info4alien.de — немецкоязычный форум для иностранцев в Германии. Народ более чем адекватный, встречаются сотрудники немецких ведомств и посольств Германии, которые могут дать очень дельный совет,
tupa-germania.ru — русскоязычный сайт, содержащий множество статей о повседневных вопросах иммигранта и их решении,
de-online.ru — русскоязычный сайт, содержащий неплохие материалы для изучения немецкого языка и форум, на котором общаются в основном на студенческо-абитуриентские темы.

Let's block ads! (Why?)