Страницы

Поиск по вопросам

четверг, 26 декабря 2019 г.

Склонение русских слов по падежам

#php #веб_программирование #веб_служба #естественный_язык


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


Ответы

Ответ 1



http://morpher.ru/php/extension/ Первая ссылка из гугла. Вроде то, что Вам подходит.

Контроль отключения сопряженного устройства по COM порту

#c_sharp


Имеется следующий код.



    public static class PortHandler
    {
        private static ConnectionType _state;

        private static SerialPort _port;

        public static void init()
        {
            _state = ConnectionType.DETACHED;

            Thread serialMonitor = new Thread(SerialMonitor);
            serialMonitor.IsBackground = true;
            serialMonitor.Start();
        }

        static void SerialMonitor()
        {
            while (true)
            {
                switch (_state)
                {
                    case ConnectionType.DETACHED:
                        scanPorts();
                        break;

                    case ConnectionType.CONNECTED:
                        FormFunctions.writeLog("Check Port. Size: " + SerialPort.GetPortNames().Length,
MessageType.INFO);

                        try
                        {
                            _port.Write(new byte[1] { 0x00 }, 0, 1);
                        }
                        catch (Exception e)
                        {
                            FormFunctions.writeLog("Fault to connect to " + _port.PortName
+ ". Exception: " + e, MessageType.INFO);
                            _state = ConnectionType.DETACHED;
                        }

                        break;
                }

                Thread.Sleep(1000);
            }
        }

        private static void scanPorts()
        {
            string[] ports = SerialPort.GetPortNames();
            if (ports.Length == 0)
            {
                FormFunctions.writeLog("Port list is empty.", MessageType.INFO);
                return;
            }

            foreach (string port in ports)
            {
                if (checkSerialPort(port))
                {
                    FormFunctions.writeLog("Port connected.", MessageType.SUCCESS);
                    _state = ConnectionType.CONNECTED;
                    break;
                }
            }
        }

        private static Boolean checkSerialPort(string name)
        {
            _port = new SerialPort(name);
            _port.BaudRate = 9600;
            _port.Parity = Parity.None;
            _port.StopBits = StopBits.One;
            _port.DataBits = 8;

            _port.Handshake = Handshake.None;
            _port.PinChanged += new SerialPinChangedEventHandler(SerialPinChangedEventHandler);

            _port.Open();

            byte[] init = new byte[4] { 0xa1, 0xa1, 0xa1, 0xa1 };

            _port.Write(init, 0, init.Length);

            return true;
        }

        private static void SerialPinChangedEventHandler(object sender, SerialPinChangedEventArgs e)
        {
            FormFunctions.writeLog("Pin Changed Event: " + e, MessageType.SUCCESS);
        }
    }




Если закомментировать все стройчки с подключением к порту и отправкой информации,
то в логах программы регистрируются все ивенты с подключением/отключением устройства
синхронно со звуком в системе. Но стоит создать подключение, то всё работает до (!)
эмуляции отвала устройства. Т.е. если я вручную выдёргиваю девайс, то получаю IO Exception
на строке _port.Open();

Лог работы программы следующий:



12.12.2017, 11:57:11 [INFO]: Port list is empty.
12.12.2017, 11:57:12 [INFO]: Port list is empty.
12.12.2017, 11:57:13 [INFO]: Port list is empty.
12.12.2017, 11:57:14 [INFO]: Port list is empty.
12.12.2017, 11:57:15 [INFO]: Port list is empty.
12.12.2017, 11:57:16 [INFO]: Port list is empty.
12.12.2017, 11:57:17 [SUCCESS]: Port connected.
12.12.2017, 11:57:18 [INFO]: Check Port. Size: 1
12.12.2017, 11:57:19 [INFO]: Check Port. Size: 1
12.12.2017, 11:57:20 [INFO]: Check Port. Size: 1
12.12.2017, 11:57:21 [INFO]: Check Port. Size: 1
12.12.2017, 11:57:22 [INFO]: Check Port. Size: 1
12.12.2017, 11:57:22 [INFO]: Fault to connect to COM15. Exception: System.IO.IOException:
Порт 'COM15' не существует.
   в System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
   в System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult)
   в System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count,
Int32 timeout)
   в System.IO.Ports.SerialPort.Write(Byte[] buffer, Int32 offset, Int32 count)
   в Infrared.common.PortHandler.SerialMonitor() в C:\...\PortHandler.cs:строка 42




Пробовал использовать ивент SerialPinChangedEventHandler, но никакой реакции на него
нет. Также пробовал принудительно завершать текущее подключение, но получаю ошибку
NPE на функции _port.Close().

Подскажите, где я неправ.

P.S. Или статический класс не подходящий пример решения моей задачи, т.к. Dispose()
с ним не работает?

P.S.S. Есть ли смысл реализовать это в инстансе на Singleton?
    


Ответы

Ответ 1



По поводу SerialPort.Open(): Работает оно маленько не так как вы ожидаете. Если устройства не будет физические или оно в не валидном состоянии(см. MSDN), то этот метод выдаст исключение. Скорее всего этот метод вызывает внутри себя апишную CreateFile. По этому можно представить поведение SerialPort.Open(), как открытие файла и так его нет соответственно выбрасывается исключение. Но есть одно но. Если у вас порт на матиринке, то он будет виден даже когда устройство не подключено. И в этом случае SerialPort.Open() скорее всего завершится без ошибок, и возможно даже ОС даст вам слать туда данные. По поводу SerialPinChangedEventHandler Судя по документации нет ни каких гарантий, что это событие будет работать со всеми устройствами или дровами. Тут я могу ошибаться так как работать с этим не приходилось. По поводу Dispose() и Singleton Вызывать Dispose() считается хорошим тоном, даже если у вас объект живет в течении всего времени работы приложения. Но в вашем примере оно в принципе не особо нужно.

Ответ 2



Должно же кому-то пригодиться. Судя из англоязычных форумов, сама Microsoft не даёт никаких гарантий на то, что сама реализация SerialPort() будет работать корректно. Это зависит от многих условностей: тип порта, драйвера, аппаратная реализация (какие каналы задействованы) и прочее, прочее, прочее. А также, стоит отметить что некоторые функции, например: SerialPort.Close() могут содержать несколько инструкций, которые могут генерировать собственные исключения. Но при этом они завершают, скажем так, начатое. Моя проблема с "залипанием" соединения на порту при "отвале" устройства (виртуальный COM порт) была решена просто: if (_port != null) { try { _port.Close(); } catch (Exception e) { // Ignore pointless exception. } _port = null; } Это необходимо добавлять в catch() блок где находится функция записи в порт. Иными словами, если запись в порт невозможна, то "убиваем не убитое". В итоге, порт освобождается и объект не содержит больше ничего. Что позволяет продолжать мониторинг "реальных" портов в системе и осуществлять повторное подключение по доступности. Со стороны это выглядит как мега костыль. P.S. Я сильно ошибался, считая Java самым убогим языком ООП. Каюсь.

Что дает наличие transform: translateZ(0) scale(1, 1) в body

#css


Не первый раз встречаю правило transform: translateZ(0) scale(1, 1), какое применяется
к тегу . 

Вопрос, что дает данное правило?   

Так как у меня от него следующий проблемы: border не всегда прорисовывается в таблице
и иногда изображения не прогружаются (случай в Google Chrome).
Но! Когда отключаешь это правило, сайт сдвигается(пока еще не понял почему, ведь
значения стандартные ИМХО).
На сайтах где-то прочитал, что это для того, чтобы мерцания не было ( но может я
не правильно понял). Спасибо
    


Ответы

Ответ 1



Без минимального, самодостаточного и воспроизводимого примера вашей конкретной ошибки сложно сказать наверняка. Обычно translateZ(0) прописывают для того, чтобы отрисовать элементы в GPU еще до того, как анимация началась, чтобы анимация была плавной, без дерганий. tranform не перерисовывает объект, он работают напрямую с GPU памятью, которая использует аппаратное ускорение. scale(1, 1) увеличивает содержимое блока в 110% от нормы. Скорее всего именно поэтому вы не видите некоторые бордеры, границы содержимого. Ведь они больше ширины блока на 10% и скорее всего просто в него не влезли. Можете попробовать прописать принудительно overflow. Возможно у вас что-то наподобие вот этого: div { height: 50px; margin: 20px; border: 5px solid red; transform: translateZ(0) scale(1.1); } .one { overflow: hidden } .two { overflow:auto } .three { overflow: visible; } span { height: 50px; display: block; border: 5px solid green; }
1
2
3


Отправить почту через .РФ домен

#c_sharp #aspnet_mvc


Для рассылки почты использовал достаточно простой метод отправки.    

public bool SendEmail(string UserName, string UserPassword, string emailTo, string
subject, string body, bool isBodyHtml)
    {
        if (string.IsNullOrEmpty(emailTo))
        {
            return false;
        }
        using (System.Net.Mail.SmtpClient smtpClient = new System.Net.Mail.SmtpClient(SERVERSMTP,
PORTNOSMTP))
        {

            smtpClient.EnableSsl = false;
            smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;                
            smtpClient.UseDefaultCredentials = false;
            smtpClient.Credentials = new NetworkCredential(UserName, UserPassword);
            using (MailMessage message = new MailMessage())
            {
                message.From = new MailAddress(UserName);
                message.Subject = subject == null ? "" : subject;                    
                message.Body = body == null ? "" : body;                    
                message.IsBodyHtml = isBodyHtml;
                message.To.Add(new MailAddress(emailTo));
                try
                {
                    smtpClient.Send(message);
                    return true;
                }
                catch (Exception exception)
                {
                    //string s1 = exception.Message + "\n" + exception.InnerException
+ "\n" + exception.Data;
                    throw new FaultException(exception.Message);
                }
            }
        }
    }


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

System.Net.WebException: Невозможно разрешить удаленное имя "мойсайт.рф" 


пробовал добавить в код    

 smtpClient.DeliveryFormat = SmtpDeliveryFormat.International;


тоже не помогло, как быть? где это разрешается? Читал про:    








Но не могу понять как это в моём случае использовать?
    


Ответы

Ответ 1



Вам нужно сконвертировать домен в Punycode. using System.Globalization; string unicode = @"россия.рф"; IdnMapping mapping = new IdnMapping(); string ascii = mapping.GetAscii(unicode); Console.WriteLine(ascii); string convertedBackToUnicode = mapping.GetUnicode(ascii); Console.WriteLine(convertedBackToUnicode);

Почему на маленьких экранах текст съезжает?

#android #xml


Сделал кнопку в ней текст , но когда запускаю на экранах входящих в диапазон Small,
например Nexsus_s, текст становится в две строки. На сколько я знаю размер текста не
спроста считается в sp  и должен сам масштабироваться. Ну выходит дело в том, что моя
кнопка позволяет тексту расползтись.  Если вместо 28  dp высоту установлю по содержимому,
то кнопка становится слишком большая.  

` `


Вот вся верстка целиком: 

    


    

    

    

        

        


    

    

        

        


    

    

        

            

            

            
        
    

    


 


Получается на маленьком экране вот так : https://gyazo.com/33a89a7d85c5b06f5affadc6a918fff1
А на больших: https://gyazo.com/1d24ac4d8f0d463f74b4f092aadfab24
    


Ответы

Ответ 1



Это происходит из за того, что текст целиком не входит в границы, указанные для виджета и система удаляет текст начиная от последнего пробела (зачем она так делает - вопрос филосовский). Есть несколько способов решить эту проблему (текст должен быть в одну строку, но на маленьких экранах он не входит): 1) Для маленьких экранов выводить другой текст (более короткая фраза, сокращения) Преимущества: заранее известный результат, нормальный размер текста для чтения Недостатки: явных нет Создаем папку res/values-hdpi/ (или с другим квалификатором, на плотности которого имеются проблемы с текстом) создаем там файл strings.xml где пишем альтернативный, более короткий текст по возрст. Для виджета указываем текст в виде ресурса: 2) Доверяем сокращение системе: Достоинства: то же, что и первый вариант Недостатки: неизвестно, как именно сократит система и будет ли это понятно в итоге 3) Уменьшаем размер текста для проблемного экрана Достоинста: сохраняется весь текст Недостатки: чтобы вместить весь текст, шрифт может быть очень маленький и плохо читаться Создаем папку res/values-hdpi/ создаем там файл dimens.xml где указываем размер текста 10sp Указываем значение для виджета: 4) Используем более компактную компоновку экрана, например в вашем случае можно использовать Spinner с выбором вариантов сортировки PS: Для первого и третьего вариантов так же обязательно должно быть указано значение по умолчанию, которое необходимо поместить в папку без квалификаторов (res/values/), файлы оформляются аналогично, значения в файлах соотвествуют нормальным условиям: текст - "по возрастанию", размер шрифта - 14sp, например.

Фоновый ввод информации C++

#cpp


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


Ответы

Ответ 1



Хорошо. Это решение выводит числа, пока не будет нажата какая-либо клавиша клавиатуры. В данной задаче очень полезен метод kbhit(). #include #include using namespace std; int main() { bool run = true; while (run) { for (int i = 1; i<1000000; i++) { if (kbhit()) { run = false; break; } cout << i << "\n"; } } system("pause"); return 0; } Если Вам необходимо, чтобы юзер ввёл именно слово "стоп", то моё решение, к сожалению, Вам категорически не подходит...

JavaFx: TreeView

#java #javafx #treeview #кастомизация


Как можно сделать такие полосы (штриховку) в TreeView? 
Перегуглил как мог, нигде и намёка нет на подобную штуку 

javafx: 
 
swing: 
 
    


Ответы

Ответ 1



Очень просто: TreeItem item=new TreeItem(new HBox(new ImageView(new Image(inputStream)),new Label("Root"))); item.getChildren().add(new TreeItem(new HBox(new ImageView(new Image(inputStream)),new Label("Item1")))); TreeView treeView=new TreeView(item); При желании можно сделать вместо HBox класс, который будет автоматически менять изображение в зависимости от строения TreeItem.

Регулярные выражения: из массива строк исключить подстроку

#c_sharp #регулярные_выражения #visual_studio


Возникла необходимость в большом куске кода внести массовую замену. Использую штатный
инструмент Visual Studio 2017 и регулярные выражения для поиска. Подразумеваю, что
синтаксис выражений в строке поиска соответствует синтаксису регулярных выражений в C#.
Есть следующая строка


  get_Label().get_UserLocalizedLabel().get_Label();


В поиске задаю выражение get_(\w*)\(\)

Получаю результат поиска:


  get_Label().get_UserLocalizedLabel().get_Label();


А нужен вот такой результат:


  get_Label().get_UserLocalizedLabel().get_Label();


То есть необходимо исключить слово между get_ и (). Пробовал get_(?!\w*)\(\), но
не преуспел.
    


Ответы

Ответ 1



Если нужно заменить get_ и () на что-то, то подойдёт такой вариант: Find what: get_(\w*)\(\) Replace with: Get$1 Для get_Label().get_UserLocalizedLabel().get_Label() результат: GetLabel.GetUserLocalizedLabel.GetLabel

Можно, ли перевести String в код java

#java #python #exec


В Python есть метод exec(), есть ли такое в Java?
    


Ответы

Ответ 1



Нет, python интерпретируемый язык программирования, в отличае от java. Инными словами для того, чтобы запусить код java, его вначале нужно скомпилировать.

Ответ 2



Из вопроса непонятно зачем работать с java в режиме интерпретации. Почитайте про JavaCompiler. В определенных случаях это может помочь.

App.config и приложение на C#

#c_sharp #net #config #clr


У меня есть небольшая программа на 2 версии .NET, но новых версиях Windows  она не
запускается, но если создать файл настроек, то она запустится.




  
  
  




Есть какие-нибудь варианты, что можно сделать, чтоб было не 2 файла, а 1? Т.е внедрить
этот файл настроек в exe или ещё как-нибудь.
    


Ответы

Ответ 1



Встроить файл конфигурации в EXE-файл нельзя (так как весь смысл конфигурации - это возможность редактирования параметров без перекомпиляции программы, такой возможности не предусмотрели). Влиять на параметр supportedRuntime из кода на C# также нельзя, так этот параметр используется неуправляемым кодом загрузчика до того, как в процесс загружена CLR, и в этот момент управляемый код еще не может выполняться. Если нужно управлять выбором версии CLR без файла конфигурации, единственный способ - написать свой собственный загрузчик на С++, пользуясь Unmanaged .NET API. Например, создадим такую программу на C#: using System; namespace ConsoleApplication1 { class Program { static int Run(string arg) { Console.WriteLine("Hello from .NET " + Environment.Version.ToString()); Console.ReadKey(); return 0; } static void Main(string[] args) { Run(""); } } } Скомпилируем ее, получаем файл Program.exe. Создадим проект С++, добавим в него файл Program.exe и создадим файл ресурсов resource.rc следующего содержания: #define IDR_RCDATA1 101 IDR_RCDATA1 RCDATA "Program.exe" Напишем на С++ код загрузчика, который находит первую установленную версию CLR, загружает ее, извлекает из ресурсов программу на C# во временную папку и запускает ее: #include #include #include #include #pragma comment(lib, "mscoree.lib") #define IDR_RCDATA1 101 int wmain(int argc, wchar_t* argv[]) { LPCWSTR prog_name = L"Program.exe"; //имя программы на C# //построим путь к временному файлу WCHAR temppath[300] = L"c:\\temp\\"; GetTempPath(300,temppath); wcscat(temppath,prog_name); //извлечем программу из ресурсов HRSRC myResource = ::FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA); UINT Size = ::SizeofResource(NULL, myResource); HGLOBAL myResourceData = ::LoadResource(NULL, myResource); void* pMyBinaryData = ::LockResource(myResourceData); FILE* f = _wfopen(temppath,L"wb"); fwrite(pMyBinaryData,Size,1,f); fclose(f); //инициализация CLR... HRESULT hr; ICLRMetaHost *pMetaHost = NULL; ICLRRuntimeInfo *pRuntimeInfo = NULL; ICLRRuntimeHost *pClrRuntimeHost = NULL; IEnumUnknown* pEnum= NULL; ICLRRuntimeInfo* pInfo= NULL; IUnknown* pUnk = NULL; hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); if(FAILED(hr)){printf("CLRCreateInstance failed\n");goto End;} //поиск установленных версий CLR... pMetaHost->EnumerateInstalledRuntimes(&pEnum); if(FAILED(hr)){printf("EnumerateInstalledRuntimes failed\n");goto End;} ULONG c= 0; WCHAR buffer[250]; DWORD cch = 250; while(1){ if(pInfo!=NULL){pInfo->Release();pInfo = NULL;} if(pUnk!=NULL){pUnk->Release();pUnk = NULL;} if(pRuntimeInfo!=NULL){pRuntimeInfo->Release();pRuntimeInfo = NULL;} hr = pEnum->Next(1,&pUnk,&c); if(hr != S_OK)break; pUnk->QueryInterface(IID_ICLRRuntimeInfo, (void**)&pInfo); if(FAILED(hr)){printf("QueryInterface failed\n");continue;} pInfo->GetVersionString(buffer,&cch); if(FAILED(hr)){printf("GetVersionString failed\n");continue;} hr = pMetaHost->GetRuntime(buffer, IID_PPV_ARGS(&pRuntimeInfo)); if(hr == S_OK){break;} else {wprintf(L".NET %s: GetRuntime HRESULT 0x%x\n",buffer,(UINT)hr);} } if(pRuntimeInfo == NULL){printf("Failed to initialize CLR\n");goto End;} /* Можно также указать версию явно, например: pMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&pRuntimeInfo)); pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); и т.п. */ hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)); if(FAILED(hr)){printf("GetInterface failed\n");goto End;} //запуск CLR hr = pClrRuntimeHost->Start(); if(FAILED(hr)){printf("Start failed\n");goto End;} //Запуск программы на C# DWORD pReturnValue; hr = pClrRuntimeHost->ExecuteInDefaultAppDomain( temppath, L"ConsoleApplication1.Program", //класс L"Run", //метод L"", //параметр &pReturnValue); if(FAILED(hr)){printf("ExecuteInDefaultAppDomain failed 0x%x\n",(UINT)hr);goto End;} End: //Освобождение ресурсов if(pMetaHost != NULL) pMetaHost->Release(); if(pRuntimeInfo != NULL) pRuntimeInfo->Release(); if(pClrRuntimeHost != NULL) pClrRuntimeHost->Release(); if(pEnum != NULL) pEnum->Release(); if(pInfo != NULL) pInfo->Release(); if(pUnk != NULL) pUnk->Release(); return 0; } В результате программа, собранная под .NET 2.0, при его отсутствии будет запускаться на имеющейся версии .NET, как и при использовании параметра supportedRuntime. Источники: Embedding supportedRuntime into exe file - ответ Ondrej Svejdar How to load a custom binary resource in a VC++ static library as part of a dll? - ответ LihO

Как перегрузить оператор для класса с произвольным типом

#c_sharp #net #tree


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

Вот код:


class Node
{
    internal T value;

    public static Node operator +(Node A, Node B)
    {
        return new Node(A.value + B.value);
    }

    public int Balance
    {
        get
        {
            if (Left == null && Right == null)
                return 0;
            else if (Left == null && Right != null)
                return 0 - Right.Height;
            else if (Left != null && Right == null)
                return Left.Height;
            return (Left.Height - Right.Height);
        }
        private set { }
    }
    public int Height
    {
        get
        {
            if (Left == null && Right != null)
                return 1 + Right.Height;
            else if (Left != null && Right == null)
                return 1 + Left.Height;
            else if (Left != null && Right != null)
            {
                if (Left.Height >= Right.Height)
                    return Left.Height + 1;
                else
                    return Right.Height + 1;
            }
            else
                return 0;
        }

        private set
        {
        }

    }


Я хочу 


сделать так, чтобы эти оператором можно было воспользоваться только если тип значения
узла Int 
не использовать для этого отдельный новый класс IntNode : Node , а сделать это
прямо в Node


Мне выводит такую ошибку: 


  Тип одного из параметров бинарного оператора должен быть вмещающим.   

    


Ответы

Ответ 1



сделать так, чтобы эти оператором можно было воспользоваться только если тип значения узла Int Невозможно. Это невозможно даже в C++ с его текстовыми шаблонами формата "найти-заменить" (оператор будет доступен, но при компиляции вывалится 10КБ текста ошибок в потрохах инклюдов). Если класс имеет разные члены в зависимости от параметров, то это не один класс. Вряд ли от этого принципа отступятся. не использовать для этого отдельный новый класс IntNode : Node, а сделать это прямо в Node Много вариантов: Построить Expression с оператором, скомпилировать. Сгенерировать IL в рантайме. Воспользоваться отражениями. Воспользоваться dynamic, который воспользуется отражениями. Чистого варианта нет. Возможно, когда-нибудь будет, но я бы не сильно надеялся, что это случится скоро: у задачи Exploration: Shapes and Extensions нет ни статуса, ни майлстона (даже "X.0").

JavaScript/Canvas Приятствие

#javascript #canvas


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



var canvas = document.getElementById("d1");
var ctx = canvas.getContext("2d");

var pressedRight = false;
var pressedLeft = false;
var pressedUp = false;
var pressedDown = false;

document.addEventListener("keydown", keyDown, false);
document.addEventListener("keyup", keyUp, false);

function keyDown(e) {
  if(e.keyCode == 37) {
    pressedRight = true;
  } else if(e.keyCode == 38) {
    pressedUp = true;
  }else if(e.keyCode == 39) {
    pressedLeft = true;
  }else if(e.keyCode == 40) {
    pressedDown = true;
  }
}

function keyUp(e) {
  if(e.keyCode == 37) {
    pressedRight = false;
  } else if(e.keyCode == 38) {
    pressedUp = false;
  }else if(e.keyCode == 39) {
    pressedLeft = false;
  }else if(e.keyCode == 40) {
    pressedDown = false;
  }
}

var player = {
  x: 10,
  y: 10,
  pW: 50,
  pH: 50,
  draw: function() {
    ctx.beginPath();
    ctx.rect(this.x, this.y, this.pW, this.pH);
    ctx.fillStyle = "black";
    ctx.fill();
    ctx.closePath();
  }
}

var block = {
  x: 200,
  y: 100,
  pW: 50,
  pH: 50,
  draw: function() {
    ctx.beginPath();
    ctx.rect(this.x, this.y, this.pW, this.pH);
    ctx.fillStyle = "green";
    ctx.fill();
    ctx.closePath();
  }
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  player.draw();
  block.draw();
  
  if(pressedRight && 0 < player.x) {
    player.x -= 3;
  }
  if(pressedLeft && player.x < canvas.height - player.pW) {
    player.x += 3;
  }
  if(pressedUp && 0 < player.y) {
    player.y -= 3;
  }
  if(pressedDown && player.y < canvas.height - player.pH) {
    player.y += 3;
  }

}

setInterval(draw, 10);
#d1 {
  border: 1px solid black;
}




    


Ответы

Ответ 1



var canvas = document.getElementById("d1"); var ctx = canvas.getContext("2d"); var pressedRight = false; var pressedLeft = false; var pressedUp = false; var pressedDown = false; document.addEventListener("keydown", keyDown, false); document.addEventListener("keyup", keyUp, false); function keyDown(e) { if(e.keyCode == 37) { pressedRight = true; } else if(e.keyCode == 38) { pressedUp = true; }else if(e.keyCode == 39) { pressedLeft = true; }else if(e.keyCode == 40) { pressedDown = true; } } function keyUp(e) { if(e.keyCode == 37) { pressedRight = false; } else if(e.keyCode == 38) { pressedUp = false; }else if(e.keyCode == 39) { pressedLeft = false; }else if(e.keyCode == 40) { pressedDown = false; } } var player = { x: 10, y: 10, pW: 50, pH: 50, draw: function() { ctx.beginPath(); ctx.rect(this.x, this.y, this.pW, this.pH); ctx.fillStyle = "black"; ctx.fill(); ctx.closePath(); } } var block = { x: 200, y: 100, pW: 50, pH: 50, draw: function() { ctx.beginPath(); ctx.rect(this.x, this.y, this.pW, this.pH); ctx.fillStyle = "green"; ctx.fill(); ctx.closePath(); } } function draw() { if(pressedRight && 0 < player.x) { player.x -= 3; //добавлена проверка на принадлежность углов Игрока к текущему контексту, //которым, в данном коде, является блок. Углы выбираются в зависимости от направления движения if(checkCrash(player.x, player.y) || checkCrash(player.x, player.y+player.pH) ){ gameOver(); return; } } if(pressedLeft && player.x < canvas.height - player.pW) { player.x += 3; if(checkCrash(player.x+player.pW, player.y) || checkCrash(player.x+player.pW, player.y+player.pH) ){ gameOver(); return; } } if(pressedUp && 0 < player.y) { player.y -= 3; if(checkCrash(player.x, player.y) || checkCrash(player.x+player.pW, player.y) ){ gameOver(); return; } } if(pressedDown && player.y < canvas.height - player.pH) { player.y += 3; if(checkCrash(player.x, player.y+player.pH) || checkCrash(player.x+player.pW, player.y+player.pH) ){ gameOver(); return; } } ctx.clearRect(0, 0, canvas.width, canvas.height); player.draw(); block.draw(); } var timerId = setInterval(draw, 10); //используется нативный метод isPointInPath, который проверяет принадлежность // точки к текущему контексту. Текущим контекстом у Вас является блок, т.к. он отрисовывается последним. function checkCrash(x,y){ return ctx.isPointInPath(x,y); } function gameOver(){ console.log("Вы проиграли"); document.removeEventListener("keydown", keyDown, false); document.removeEventListener("keyup", keyUp, false); clearInterval(timerId); } #d1 { border: 1px solid black; }

Ошибка при переводе выражения в обратную польскую запись

#cpp #алгоритм #польская_запись


Имеется код:

#include 
#include 
using namespace std;
struct stack {
    char info;
    stack* next;
};
void addToStack(char sym, stack *&begin);
void showStack(stack *begin);
int priority(char op);
void showElementsInBrackets(string &output, stack *&begin);
void executeFromStackElements(string &output, stack *&begin);
int main() {
    stack *begin = NULL;
    string input, output = "";
    cin >> input;
    for (int i = 0; i < input.length(); i++) {
        if (input[i] >= 'a' && input[i] <= 'z') {
            output += input[i];
        }
        else if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i]
== '/' || input[i] == '%' || input[i] =='(') {
            if (begin == NULL || input[i] == '(') {
                addToStack(input[i], begin);
            }
            else {
                if (priority(begin->info) <= priority(input[i])) {
                    addToStack(input[i], begin);
                }
                else {
                    executeFromStackElements(output, begin);
                    addToStack(input[i], begin);
                }
            }
        }
        else if (input[i] == ')') {
            showElementsInBrackets(output, begin);
        }
    }
    executeFromStackElements(output, begin);
    cout << "Output:" << endl;
    cout << output << endl;
    system("pause");
    return 0;
}

void addToStack(char sym, stack *& begin)
{
    stack *t = new stack;
    t->info = sym;
    t->next = begin;
    begin = t;
}

void showStack(stack * begin)
{
    stack *t = begin;
    while (t != NULL) {
        cout << t->info << endl;
        t = t->next;
    }
}

int priority(char op)
{
    if (op == '(') {
        return 1;
    }
    else if (op == '+' || op == '-') {
        return 2;
    }
    else if (op == '*' || op == '/' || op == '%') {
        return 3;
    }
}



void showElementsInBrackets(string & output, stack *& begin)
{
    while (begin->info != '(' && begin != NULL) {
        output += begin->info;
        begin = begin->next;
    }
    begin = begin->next;
}

void executeFromStackElements(string & output, stack *& begin)
{
    while (begin != NULL) {
        output += begin->info;
        begin = begin->next;
    }
}


Задача - перевод выражения в ОПЗ. Однако при определенном вводе, возникают проблемы
со скобками. Например, при вводе a+bcd+(e-f)(gh+i), возникает 
ошибка 


  Вызвано исключение по адресу 0x010F3CD3 в OPZ.exe: 0xC0000005:
  нарушение прав доступа при чтении по адресу 0x00000000.
  И указывает на строку 


while (begin->info != '(') {


Смотрю по отладке, там выходная строка это abcd**+ef-gh*(*+i+
Как я понимаю, ошибка из-за того, что открывающая скобка извлекается из стека, но
не понимаю, почему это происходит
    


Ответы

Ответ 1



первая ошибка: stack *begin = NULL; поскольку после прочтения буквы в следующем цикле begin остается нулевым, а компилятор не сможет осуществить проверку: else { if (priority(begin->info) <= priority(input[i])) //... поэтому: stack *begin = new stack; и не связанные с вашим вопросом ошибки:` вторая ошибка: вы нигде не удаляете обьекты, созданные в свободной области памяти через new, т.е. обьекты стека. третья ошибка: вы не возвращаете из функции int priority(char op) ничего, если op не является ни один из вами перечисленных символов (лучше возвращать ноль и это использовать в ваших условиях, т.е. если priority(char op)== 0, значит` op не является символом математической операции и напоследок: еслибы вы хранили один string("*/()%+-"}, то использовав string::find могли бы сделать этот же код компактней и с меньшим количеством if/else ов

Ответ 2



Забыли проконтролировать скобки в executeFromStackElements. void executeFromStackElements(string & output, stack *& begin) { while (begin != NULL and begin->info != '(') { output += begin->info; begin = begin->next; }}

Перевод SQL запроса в LINQ

#c_sharp #sql #net #entity_framework #linq


Здраствуйте. Есть такой SQL запрос

SELECT e."Id", e."FirstName", e."SecondName", e."Patronymic",
s."DeptName" AS MainSubdivision, 
CASE WHEN s."Id" = ss."Id" THEN NULL ELSE ss."DeptName" END AS SubordinateSubdivision
FROM "Subdivisions" AS s
JOIN "Subdivisions" AS ss
ON s."Id" IN (ss."IdSubordinate", ss."Id")
JOIN "PositionEmployees" AS pe
ON pe."IdSubdivision" = ss."Id"
JOIN "Employee" AS e
ON e."Id" = pe."IdEmployee"
WHERE s."IdSubordinate" IS NULL


Я пытаюсь перевести его в LINQ но не совсем понимаю как реализовать вот такую операцию
ON s."Id" IN (ss."IdSubordinate", ss."Id")
Буду очень признателен за помощь 
вот схема БД и модели из EntityFramework

public class Subdivisions
{
    public Subdivisions()
    {
        InverseIdSubordinateNavigation = new HashSet();
        PositionEmployees = new HashSet();
    }

    public long Id { get; set; }
    public long? IdSubordinate { get; set; }
    public string DeptName { get; set; }

    public Subdivisions IdSubordinateNavigation { get; set; }
    public ICollection InverseIdSubordinateNavigation { get; set; }
    public ICollection PositionEmployees { get; set; }
}

public class PositionEmployees
{
    public long Id { get; set; }
    public long IdEmployee { get; set; }
    public long IdSubdivision { get; set; }

    public Employee IdEmployeeNavigation { get; set; }
    public Position IdPositionNavigation { get; set; }
    public Subdivisions IdSubdivisionNavigation { get; set; }
}

public class Employee
{
    public long Id { get; set; }
    public string FirstName { get; set; }
    public string SecondName { get; set; }
    public string Patronymic { get; set; }

    public PositionEmployees PositionEmployees { get; set; }
}



    


Ответы

Ответ 1



var q = from s in Subdivisionsess from ss in Subdivisionsess where s.Id == ss.Id || s.Id == ss.IdSubordinate join pe in PositionEmployeesess on ss.Id equals pe.IdSubdivision join e in Employees on pe.IdEmployee equals e.Id where s.IdSubordinate == null select new { e.Id, e.FirstName, e.SecondName, e.Patronymic, MainSubdivision = s.DeptName, SubordinateSubdivision = s.Id == ss.Id ? null : ss.DeptName }; Но на самом деле вы не должны так никогда писать (вся эта куча JOIN), вы должны пользоваться навигационными свойствами. Если вы опишите словами более подробно что делает ваш запрос, то вам напишут как правильно это сделать с помощью Linq

Ответ 2



навскидку, так: var result = from s in subdivisions join ss in subdivisions on s.Id equals ss.Id join sss in subdivisions on s.Id equals sss.IdSubordinate //! "X equals Y" ни в коем случае не менять местами ХЪ join pe in positionEmployees on ss.Id equals pe.IdSubdivision join e in employee on pe.IdEmployee equals e.Id where s.IdSubordinate != null select new { e.Id, e.FirstName, e.SecondName, e.Patronymic, MainSubdivision = s.DeptName, SubordinateSubdivision = (s.Id == ss.Id) ? null : ss.DeptName };

Содержит ли normal elements - custom elements?

#html


Входит ли custom elements в группу normal elements?

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

В пункте сказано: 


  Normal elements: All other allowed HTML elements are normal elements


В этой ссылке говорится что любые определения в пространстве содержатся в http://www.w3.org/1999/xhtml 

А также цитата: 


  The term "HTML elements" refers to any element in that namespace, even in XML documents.


Но вот определения custom elements нет в http://www.w3.org/1999/xhtml , значит ли
это что custom elements не входит в группу normal elements?
    


Ответы

Ответ 1



Все исходит из того, что XHTML является подмножеством языка XML. В языке XML вы можете создавать и использовать абсолютно любые теги, которые только ваша душа пожелает. Это Custom Elements: <Планеты> <Планета ID="1"> <Название>Меркурий <Планета ID="2"> <Название>Сатурн А в XHTML прописаны только известные браузерам теги для которые он может генерировать внешний вид, эти элементы называются Normal Elements: Заголовок Содержимое документа То есть по факту Custom Elements это огромная группа элементов в которую так же (теоретически) входят и Normal Elements. Но шанс встретить Custom Elements в разметке мизерный. Правда стандарт HTML накладывает ограничения на имена Custom Elements: RuSO: Нестандартные HTML теги

GNU Readline, статическое подключение к Qt

#linux #qt #qtcreator #readline


Имеется Qt Creator с собранным Qt с флагом -static. Библиотеки qt успешно вшиваются
в программу, а вот readline (GNU Readline) никак не желает. Каким образом надо настроить
.pro - файл, чтобы readline вшилась в программу?

ОС: Ubuntu 14.xx. Файл libreadline.a в системе есть. 

P.S.: проект с открытым исходным кодом будет, так что про GNU в курсе.
    


Ответы

Ответ 1



Сразу предупреждаю, на ответ не тянет, но в комментарий не поместится. Собрал тест с readline (но без QT -)). В самом деле gcc -o t-r t-readline.c -static -lreadline выдает предупреждения для некоторых функций libc (связанных с аутентификацией) и ошибки на отсутствие функций tgetent, tputs, tgetflag и т.п., вызываемых из функций библиотеки readline. Понятно, что я не задал линкеру какую-то библиотеку (или несколько). Узнать, какие библиотеки нужны помогает утилита ldd (print shared object dependencies). Итак, собираем shared версию gcc -o t-r t-readline.c -lreadline и запускаем ldd avp@avp-ubu1:hashcode$ ldd -v ./t-r linux-vdso.so.1 => (0x00007ffeb73e5000) libreadline.so.6 => /lib/x86_64-linux-gnu/libreadline.so.6 (0x00007fb39dd17000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb39d94d000) libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fb39d724000) /lib64/ld-linux-x86-64.so.2 (0x00007fb39df5d000) Version information: ./t-r: libc.so.6 (GLIBC_2.7) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libreadline.so.6: libtinfo.so.5 (NCURSES_TINFO_5.0.19991023) => /lib/x86_64-linux-gnu/libtinfo.so.5 libc.so.6 (GLIBC_2.11) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.15) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6: ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2 ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/libtinfo.so.5: libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.16) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6 Из полученного вывода делаем предположение, что скорее всего нам нужна libtinfo. Пробуем avp@avp-ubu1:hashcode$ gcc -o t-r t-readline.c -static -lreadline -ltinfo /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function': (.text+0x3f69): warning: Using 'getpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(tilde.o): In function `tilde_expand_word': (.text+0x1c4): warning: Using 'getpwnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(shell.o): In function `sh_get_home_dir': (.text+0xf9): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function': (.text+0x3f5f): warning: Using 'setpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function': (.text+0x4009): warning: Using 'endpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking avp@avp-ubu1:hashcode$ смотрим результат avp@avp-ubu1:hashcode$ file t-r t-r: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=e0ee17d4201c7070bf650e9ac2bac441f6628a51, not stripped avp@avp-ubu1:hashcode$ потом слегка "тестируем" avp@avp-ubu1:hashcode$ ./t-r > djjdjj line: djjdjj > kdkk dkkdkk dk line: kdkk dkkdkk dk > kdkk dkkm 49949 dkk dk line: kdkk dkkm 49949 dkk dk > End avp@avp-ubu1:hashcode$ и видим, что затея удалась. P.S. Warnings, наверное, тоже можно побороть.

Перетаскивание картинок и ссылок в textarea

#javascript #jquery #drag_n_drop #textarea


Есть textarea. Если перетащить в нее картинку или ссылку, то в том месте, где отпустим
мышь появится выделенный полный путь.





image

link

Как вмешаться в этот процесс, получить этот путь и видоизменить его, например обернуть в скобки перед вставкой? При этом важно, чтобы он вставлялся именно туда, куда его «дропаешь», а не в конец textarea и НЕ хочется использовать jQuery.UI


Ответы

Ответ 1



/* Получение информации об объекте перетаскивания и использование её для вставки в текстовое поле. No JQ. JS only. */ var oTextarea = document.querySelector('#text'); var sOriginalText, sInsertText; document.addEventListener('dragstart', function(event) { // Запоминаем исходный текст "textarea" sOriginalText = oTextarea.value; // Получаем от захваченного элемента данные // (здесь можно вносить нужные изменения и получить // различную информацию об объекте перетаскивания) sInsertedText = event.target.outerHTML || window.getSelection().toString(); // Проверка на перетаскивание текста внутри "textarea" if (event.target == oTextarea) { sInsertedText = window.getSelection().toString(); } }); document.addEventListener('drop', function(event) { let data = event.dataTransfer.items; for (let i = 0; i < data.length; i++) { if ((data[i].kind == 'string') && (data[i].type.match('^text/plain'))) { data[i].getAsString(function(str) { // Получаем изменённый текст "textarea" let sChangedText = oTextarea.value; // Получаем длину изменённого текста let nChangedLen = sChangedText.length; // Получаем длину исходного текста let nOriginalLen = sOriginalText.length; // Позиция каретки let nCarretPos; // Ищем изменения одновременно... for (let i = 0; i < nOriginalLen; i++) { // ... с начала if (sChangedText[i] != sOriginalText[i]) { nCarretPos = i; break; } // ...и с конца if (sChangedText[nChangedLen - 1 - i] != sOriginalText[nOriginalLen - 1 - i]) { nCarretPos = nOriginalLen - i; break; } } // (Здесь любые манипуляции с sInsertedText: replace и т.п.) // Заносим готовый текст в "textarea" oTextarea.value = sOriginalText.substring(0, nCarretPos) + sInsertedText + sOriginalText.substring(nCarretPos); // Выделяем изменения oTextarea.focus(); oTextarea.setSelectionRange( // (Если приплюсовать длину, то каретка встанет в конец вставки, ничего не выделяя) nCarretPos, // (Если не плюсовать длину, то каретка встанет в начало вставки, ничего не выделяя) nCarretPos + sInsertedText.length ); }); } } }); // Сброс (для удобства демо) var sSourceText = oTextarea.value; document.querySelector('button').addEventListener('click', function() { oTextarea.value = sSourceText; });

image

Ссылка Просто текст



Kак активировать Aякс при нажатие Enter в поле input

#javascript #html #ajax


Надо отправлять Aяксом инфу из поля  на сервер (при этом, при нажатии на Enter,
должна отправляться эта инфа) без использования 
.


Ответы

Ответ 1



Примерно так var element = document.querySelector("input"); element.addEventListener('keydown', function(e){ var key = e.keyCode ? e.keyCode : e.which; if (key == 13) { var request = new XMLHttpRequest(); var formData = new FormData(); formData.append("input", this.value) request.open("POST", "url"); request.send(formData); } });

Ответ 2



В общем выглядеть это должно как-то так. url, headers, method , и все остальные параметры смотри в доккументациик методу fetch. некоторые из этих параметров у тебя будут другие. может не самое красивое решени..но.. что нашел, то прислал))) function ajax(url,data,callback){ var formData = new FormData(); let heder = new Headers({ 'Access-Control-Allow-Origin': '*' }); formData.append('action', JSON.stringify(data)); fetch(url, { method: 'post', headers: heder, credentials: "same-origin", body: formData, }).then(validateResponse).then(function(result) { if(typeof callback === 'function') { return callback(result.result); } }); function validateResponse(response) { if(!response.ok) { throw Error(response.statusText); } return response.json(); } } let input = document.getElementById('text'); input.addEventListener('keydown',(event)=>{ if(event.keyCode===13){ ajax('http://example.com',event.target.value,()=>{}); } })

Ответ 3



Какой вопрос - такой ответ Добавить к инпуту прослушивание события и используя фетч или xhr отправлять ©"ину из поля на сервер".

Выполнять действие пока нажата кнопка

#java #javafx


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

if(pressed){
    Thread.sleep(100);
    doIt();
}


Это остановит поток пользовательского интерфейса. Значит это надо перенести в другой
поток. 

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

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

Может есть другие разумные способы решить данную задачу? Идеально если бы был какой-то
функционал отложенной задачи, по типу __Platform.runLater__ , но только выполнить задачу
через 100 мс, но я ничего подобного не нашел.
    


Ответы

Ответ 1



Написал вот такую вот конструкцию. private Thread pressingThread; @FXML void onPress() { System.out.println("do something"); final int initDelay = 200; final int repeatDelay = 50; pressingThread = new Thread(() -> { try { Thread.sleep(initDelay); while (true) { Platform.runLater(() -> System.out.println("do something again")); Thread.sleep(repeatDelay); } } catch (InterruptedException ignored) { } }); pressingThread.setDaemon(true); pressingThread.start(); } @FXML void onRelease() { pressingThread.interrupt(); } Создается поток, который ждет необходимое время, потом в бесконечном цикле передает управление в поток пользовательского интерфейса нужное действие. Чтобы завершить работу необходимо вызывать метод interrupt(). Пробовал реализовать через переменную pressed, которая хранила бы состояние кнопки, и потом проверять не зажата ли кнопка, но тут есть тонкость, что если быстро нажать дважды на кнопку, то можно создать два потока, которые будут думать что кнопка не была отпущена. Потому все равно придется использовать interrupt(). Ред. Переписал в более удобный вид import javafx.application.Platform; public class DoWhilePressed { private int initDelay = 200; private int repeatDelay = 50; private Runnable doWhilePressed = ()->{}; private Thread pressingThread; private pressed = false; public void press(){ if(pressed)return; pressed = true; doWhilePressed.run(); pressingThread = new Thread(() -> { try { Thread.sleep(initDelay); while (true) { Platform.runLater(() -> doWhilePressed.run()); Thread.sleep(repeatDelay); } } catch (InterruptedException ignored) { } }); pressingThread.setDaemon(true); pressingThread.start(); } public void release(){ pressed = false; pressingThread.interrupt(); } public int getInitDelay() { return initDelay; } public DoWhilePressed setInitDelay(int initDelay) { this.initDelay = initDelay; return this; } public int getRepeatDelay() { return repeatDelay; } public DoWhilePressed setRepeatDelay(int repeatDelay) { this.repeatDelay = repeatDelay; return this; } public Runnable getDoWhilePressed() { return doWhilePressed; } public DoWhilePressed setDoWhilePressed(Runnable doWhilePressed) { this.doWhilePressed = doWhilePressed; return this; } } Использовать можно как private DoWhilePressed doWhilePressed = new DoWhilePressed() .setInitDelay(300) .setRepeatDelay(30) .setDoWhilePressed(() -> System.out.println("pressed")); @FXML void onPress() { doWhilePressed.press(); } @FXML void onRelease() { doWhilePressed.release(); }

Qt под android 7+

#android #cpp #qt #qt5 #android_permissions


Всем доброго времени суток.
Занимаюсь разработкой qt под android и начал сталкиваться с проблемой отсутствия
интернета на андроид 7 и выше в приложении, при том что интернет в телефоне есть.
Вот вопрос, который уже поднимал здесь, но его решение рассчитано на android studio,
а не на qt:
internet android 7+
Как можно запросить права на интернет в рантайме(qt 5.10.1)? пытаюсь это сделать
такой конструкцией, но результата нет:

#include "my_app.h"
#include 
#ifdef ANDROID
#include 
#endif
#include 

bool checkPermission(const QString& perm)
{
#ifdef ANDROID
QtAndroid::PermissionResult r = QtAndroid::checkPermission(perm);
if(r == QtAndroid::PermissionResult::Denied)
{
    QtAndroid::requestPermissionsSync( QStringList() << perm );
    r = QtAndroid::checkPermission(perm);
    if(r == QtAndroid::PermissionResult::Denied)
    {
        QMessageBox::information(0, "Ошибка", "получить разрешение не           
 удалось");
         return false;
}
}
#endif
return true;
}


int main(int argc, char *argv[])
{

checkPermission("android.permission.ACCESS_WIFI_STATE");
checkPermission("android.permission.ACCESS_NETWORK_STATE");
checkPermission("android.permission.INTERNET");

QApplication a(argc, argv);
MyApp w;
w.show();

return a.exec();
}

    


Ответы

Ответ 1



Всё оказалось банально. В android 7+ нет поддержки ssl "из коробки" (google убрал). Обычный http заработал без проблем

Где реализован IEnumerator?

#c_sharp #коллекции


У меня появился вопрос, который не дает мне покоя вот уже несколько часов. Для того,
чтобы использовать foreach для кастомной коллекции, нужно реализовать метод интерфейса
IEnumerable. 

IEnumerator IEnumerable.GetEnumerator(){
        return arr.GetEnumerator();
    }


С этим все ясно. Но какой класс реализует интерфейс IEnumerator? По началу я думал
System.Array, но после того, как я не увидел IEnumerator в списке родителей System.Array
решил обратиться сюда. 
    


Ответы

Ответ 1



IEnumerator реализован типом, объект которого возвращает arr.GetEnumerator(). IEnumerator IEnumerable.GetEnumerator() { IEnumerator result = arr.GetEnumerator(); Console.WriteLine(result.GetType().FullName); return result; } Тип возвращаемого объекта - System.Array.SZArrayEnumerator. Вот этот SZArrayEnumerator и реализует IEnumerator.

Как “нащупать дно” (отследить момент касания конца страницы) при скроллинге на мобильном устройстве?

#javascript #jquery #scroll #мобильная_разработка


Подобная конструкция работает только для стационарной версии:

$(window).scroll(function() {
    if ($(window).scrollTop() + $(window).height() >= $(document).height()) {
        ...


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

Каким образом можно "словить" этот момент?
    


Ответы

Ответ 1



Запускал локальный сервер с помощью Gulp, на компе брузер Chrome работает, на мобилке браузер Safari на Iphone7 работает. $(window).on('scroll', function(e){ if ($('html, body').scrollTop()+$(window).height() == document.documentElement.scrollHeight) { $('body').append('

lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem

') } }); p{ color: coral; }

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim voluptate ex unde. Ex tenetur veniam dolores enim, tempore deserunt provident. Suscipit non quaerat blanditiis impedit, voluptatibus mollitia odio voluptates sequi. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, qui ratione vel ullam saepe odio, eveniet sapiente quas libero cum ipsa, minus a magni. Atque, vitae ipsum nihil facilis earum.



Ответ 2



if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) { $(window).scroll(function() { var crntHeight = $(this).children("#place").height(); if($(this).scrollTop() >= (crntHeight - $(this).height()-100)){ ... {ajax} ... Примерно такая конструкция работает на мобильном. Правда не идеально. Может быть есть у кого-то наработки?

Как проверить в JS-коде, есть ли на элементе обработчик onclick?

#javascript #javascript_events


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

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


Ответы

Ответ 1



К сожалению, нет стандартного апи, для получения списка всех обработчиков из кода. 1 вариант: Через консоль, тот же хром предоставляет апи getEventListeners window.getEventListeners(button); 2 вариант Если обработчик добавлен напрямую через on{event}, то можно попробовать проверить, является ли нужное св-во функцией typeof button.onclick === "function" 3 вариант ( которого нет ) Если событие добавлено через addEventListener, то тут все еще хуже. Потому что отследить такой момент вроде как не возможно. Вы можете переписать стандартную функцию addEventListener, что бы при вызове элемент и событие добавлялся в массив, откуда потом можно достать данные ( по сути getEventListeners возвращает примерно такой же объект ) const eventListeners = new Map(); EventTarget.prototype.addEventListener_ = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function (eventName, fn) { let event = eventListeners.get(this); if(!event) { event = {} } let eventData = event[eventName]; if(!eventData) { eventData = [{listener: fn}]; } else { eventData.push({listener: fn}); } event[eventName] = eventData; eventListeners.set(this, event); EventTarget.prototype.addEventListener_.call(this, eventName, fn); } const button = document.querySelector('input'); button.addEventListener('click', e => { alert('click'); showListeners(button); }); // можем посмотреть обработчики в eventListeners const showListeners = node => { if(!eventListeners.has(node)) return null; const events = eventListeners.get(node); Object.keys(events).forEach(e => { console.log(`event ${e} has length ${events[e].length}`); }); }

ppp и его маршруты

#linux #сеть #centos #ppp #ipsec


Настроил libreswan (ipsec) + xl2tp в качестве клиента до одного провайдера. Поднимается
ikev1 шифрованый канал, через него поднимается ppp тунель и дальше мне приходится прописывать
роут через тунельную сеть, что я делаю скриптом

    function route_add () {
        ip r a 192.168.10.88 via 172.16.0.1 dev ppp0
    }

    ip r | grep -q "192.168.10.88"
    if [ $? -ne 0 ]
    then
        route_add
        sleep 5
    fi

    /bin/ping -q -c 3 192.168.10.88 >/dev/null 2>&1
    if [ $? -ne 0 ]
    then
        echo "d provider" > /var/run/xl2tpd/l2tp-control
        sleep 1
        service xl2tpd restart

        sleep 5
        route_add
    fi


Этот скрипт запускается по крону и "чинит" тунель в случае его падения, а такое,
к сожалению, иногда случается. 

А что делать, если тунелей у меня там будет 100500? Как роуты прокидывать в этом
случае? Я не могу гарантировать что одному тунелю будет присвоен всегда ppp0, второму
ppp1 и т.д. Может есть способ как-то xl2tp заставить роуты прописывать? Но тогда всё
равно вопрос с watchdog'ом остаётся актуален.
    


Ответы

Ответ 1



Способ 1 создайте файл : /etc/ppp/ip-up.d/0010routes #!/bin/sh echo $@ > /tmp/last-ppp-ip-up-args env > /tmp/last-ppp-ip-up-env if [ "$PEERNAME" -eq "username" ] ; then ; ip r d 192.168.0.0/24 metric ${metric} ip r a 192.168.0.0/24 metric ${metric} via $5 dev $1 fi $PEERNAME - логин ppp $5 - ip пира $1 - имя девайса Способ 2 Установи bird apt install bird в файл /etc/bird/bird.conf добавить protocol static { route 192.168.129.0/24 via 192.168.94.36; } При появлении маршрута до 192.168.94.36 bird добавит маршрут сразу.

Что такое плоский код?

#java #терминология #чистый_код


Хорошо писать плоский код или плохо? Есть примеры плоского кода на Java?
Может кто-нибудь знает, почему он так называется?
    


Ответы

Ответ 1



Плоский или линейный код - это код, в котором операции выполняются последовательно без вложенности конструкций, например: a.soSmth(1, 2, 3); b = a.clone(); b.doSmth(4, 5, 6); c.setX(311);

Регулярные выражения Python - идем обратно

#python #регулярные_выражения


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

Пример:

"Заключение:
1
2
3
Подпись"


Мне надо оттолкнуться от Подпись и идти вверх по тексту, чтобы достать значения 3, 2, 1.

Каким образом это можно сделать?
    


Ответы

Ответ 1



Всегда, когда кажется, что нужно "найти ключевое слово, но двигаться не вперед по тексту, а обратно", нужно подумать о том, как "найти все подстроки, удовлетворяющие нужному шаблону, после которых следует ключевое слово". Некоторые библиотеки регулярных выражений могут начинать поиск с конца строки к её началу, при этом не инвертируя текст, т.е. направление чтения шаблонов в регулярке остается неизменным - слева направо. Таким образом, в данном случае проблема такова: найти все числа, которые разделены символом перевода строки, вплоть до строки, начинающейся со слова Подпись. Используйте для первого такого совпадения (демо): print(re.search(r'(?m)^(\d[\d\r\n]*)^Подпись', s).group(1).split()) Или все возможные подстроки: print(re.findall(r'(?m)^\d+(?=[\d\r\n]*^Подпись)', s)) См. демо регулярного выражения См. демо на Python. В первом примере (?m)^(\d[\d\r\n]*)^Подпись находит начало строки (или позицию после перехода строки), затем захватывает любую цифру и 0+ переходов строки или цифр, а затем находит Подпись в начале строки. Затем значение первой подгруппы разбивается по пробельным символам. Во втором случае ищутся все цифры от начала строки, за которыми следуют 0+ цифр или переходов строки, за которыми следует слово Подпись.

datetime.strptime

#python #python_3x #datetime


Есть строка:

date_ = "2018-10-22 11:34:22.393092+03"


Я с помощью datetime.strptime пытаюсь привести ее к формату datetime.datetime:

normal = datetime.strptime(date_, "%Y-%m-%d %H:%M:%S.%f%z")


Но получается исключение:


ValueError: time data '2018-10-22 11:34:22.393092+03' does not match format '%Y-%m-%d
%H:%M:%S.%f%z'



Получается оно из-за тайм зоны +03, она, как я понял, не подходит к моему формату.
Как правильно вставить %z в этот формат, чтобы все приводилось корректно?
    


Ответы

Ответ 1



Можно через модуль dateutil: # pip install python-dateutil import dateutil.parser dt = dateutil.parser.parse('2018-10-22 11:34:22.393092+03') print(dt) # 2018-10-22 11:34:22.393092+03:00 print(type(dt)) #

Временная шкала на html

#html #css #laravel #vuejs




Как реализовать подобную шкалу времени на html с добавлением 'красных участков'

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

На bootstrap получилось сделать что-то подобное(Закинул на jsfiddle, внутри SO не
работает)

На сколько это 'правильная' реализация?

Шкала нужна для вывода планов на день

Есть таблица с планами, в ней есть столбцы date_start и date_finish

Дата храниться подобным образом 2018-11-09 10:00:00

Выбираем желаемую дату и смотрим, что на эту дату запланировано. Простой вывод сделан(на
скрине справа). На скрине шкала не подключена(Тестирую)


UPD ---

Во что у меня получилось:

Контроллер:

  $rez = Plan::whereDate('date_start', '>=', $plan_day)
                ->whereDate('date_start', '<=', $plan_day)
                ->get();//Достаем планы за определенное число
  foreach ($rez as $item) {
    $date_start_h = date("H", strtotime($item->date_start));
    $date_finish_m = date("i", strtotime($item->date_finish));
    if($date_start_h == 9) {
      $progress['nine'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 10) {
      $progress['ten'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 11) {
      $progress['eleven'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 12) {
      $progress['twelve'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 13) {
      $progress['thirteen'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 14) {
      $progress['fourteen'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 15) {
      $progress['fifteen'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 16) {
      $progress['sixteen'][] = ($date_finish_m*100)/60;
    } else if($date_start_h == 17) {
      $progress['seventeen'][] = ($date_finish_m*100)/60;
    }
  }
  $v['progress'] = $progress;
  return $v;


Вывод (planDay.progress равен $v['progress'] из контроллера):

9:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Вот что получилось на скрине: Появилось несколько проблем: 1)Не учтена дата начала, на скрине это Элегант, дата начала с 12:20 до 12:30 - на шкале он не учитывает 12:20, отсчет начинает с начала и до 30 2)Выделения на шкале используют 100 процентов, для выделения я использую минуты, максимальное значение в минутах это 60. Получается если будет например с 12:00 до 12:50, на шкале это будет 50% хотя 83% Перевел минуты в проценты (минуты*100)/60 3)Если план будет с 12:00 до 13:00 все сломается 4)Как-то слишком много кода


Ответы

Ответ 1



Так как рабочих решений на html+css выдвинуто не было, предлагаю решение на canvas const time = { "11:00": [ [0, 20], [40, 60] ], "12:00": [ [10, 20], [30, 40], [50, 60] ], "13:00": [ [0, 60] ], "14:00": [], "15:00": [], "16:00": [ [25, 47] ] }; window.addEventListener('resize', () => timeLine(time, "c")); timeLine(time, "c") function timeLine(time, canvasID) { const canvas = document.getElementById(canvasID); const c = canvas.getContext('2d'); const num = Object.keys(time).length; const img = document.createElement("img"); img.src = "https://image.ibb.co/eH3VCA/img-2018-11-22-18-03-12.png"; img.onload = function() { const ptrn = c.createPattern(img, 'repeat'); // Create a pattern with this image, and set it to "repeat". c.canvas.width = parseInt(getComputedStyle(canvas).width); c.canvas.height = parseInt(getComputedStyle(canvas).height); c.font = "10px Comic Sans MS"; c.lineWidth = 1; c.strokeStyle = "black"; const unitWidth = c.canvas.width / num; const tlh = c.canvas.height - 20; // tlh = timeline height let i = 0; for (let t in time) { if (time[t].length !== 0) { c.fillStyle = ptrn; time[t].forEach((it) => { c.fillRect(unitWidth * i + unitWidth / 60 * it[0], "0", unitWidth / 60 * (it[1] - it[0]), tlh); }) } c.fillStyle = 'green'; c.fillText(t, unitWidth * i, (2 * tlh + 20) / 2); i++; } //Draw vertical lines for (i = 0; i <= num; i++) { let x = unitWidth * i; // Check the first and last lines; x = x === 0 ? c.lineWidth / 2 : i === num ? (c.canvas.width - c.lineWidth / 2) : x; c.beginPath(); c.moveTo(x, 0); c.lineTo(x, tlh); c.stroke(); } // Top and bottom lines c.beginPath(); c.moveTo(c.lineWidth / 2, c.lineWidth / 2); c.lineTo(c.canvas.width, c.lineWidth / 2); c.moveTo(c.lineWidth, tlh - c.lineWidth / 2); c.lineTo(c.canvas.width, tlh - c.lineWidth / 2); c.stroke(); } } canvas { width: 100%; height: 70px; }

Оптимальный формат изображений на сайте

#frontend #изображения #pagespeed_insights


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


Тестирование инструментом PageSpeed Insights
Измерение общего объема сайта до и после оптимизации изображений. 


Знаю 4 основных формата изображений используемых в Web:


JPEG
GIF
PNG
SVG


В основном использую именно JPEG и PNG. Поэтому занимался оптимизацией именно их.
Этого вроде бы хватало. Но совсем недавно PageSpeed Insights изменился кардинально,
например данное обновление описано на Хабре. Ранее были рекомендации по сжатию изображений,
сейчас же Google рекомендует использовать современные форматы изображений JPEG 2000,
JPEG XR и WebP.


  Используйте современные форматы изображений
  
  Для изображений в форматах JPEG 2000, JPEG XR и WebP используется
  более эффективное сжатие, поэтому они загружаются быстрее и потребляют
  меньше трафика, чем изображения PNG и JPEG.



От предлагаемых форматов изображений я просто в шоке. 



Главные проблемы, которые меня беспокоят:


Поддержка браузерами
Размер изображений


Разберёмся со всеми пунктами по порядку. 

Пункт №1

Для анализа поддержки браузерами буду использовать сервис Can I use.

Результат формата изображений JPEG - не дал результатов

Результат формата изображений PNG


Результат формата изображений JPEG 2000

Результат формата изображений JPEG XR

Результат формата изображений WebP

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

Пункт №2
В этом пункте использовав одно изображение в JPEG, я переконвертировал его в разные
форматы. 

Изображение в формате JPEG

Размер 1,26 МБ
Ссылка https://ibb.co/bxGFh0


Изображение в формате PNG

Размер 6,97 МБ

Ссылка https://ibb.co/etc7Uf

Изображение в формате JPEG 2000

Размер 2,71 МБ

Изображение в формате JPEG XR

Размер 10,4 МБ 

Изображение в формате WebP

Размер 704 КБ



Использовать JPEG, GIF, PNG, SVG или JPEG 2000, JPEG XR, WebP? Как?
    


Ответы

Ответ 1



Можно использовать в Adobe Photoshop встроенный оптимизатор "для Web", при сохранении изображения. Возможна гибкая настройка по соотношению качество-вес/скорость

Скролл вниз по нажатию кнопки

#javascript #html #css


Есть landing page. такой html:

И такой скрипт: (function() { 'use strict'; var btnScrollDown = document.querySelector('.submit'); function scrollDown() { var windowCoords = document.documentElement.clientHeight; (function scroll() { if (window.pageYOffset < windowCoords) { window.scrollBy(0, 10); setTimeout(scroll, 10); } if (window.pageYOffset > windowCoords) { window.scrollTo(0, windowCoords); } })(); } btnScrollDown.addEventListener('click', scrollDown); })(); После нажатия на Get Started должен происходить скролл до раздела контакты, внизу, но скролл идет только одну секунду до ближайшего блока. Как нужно изменить значения в скрипте чтобы скролл длился дольше? вот html, области контакты:


Ответы

Ответ 1



Данный способ совмещает в себе два "скролла до элемента": "Стандартный" (или target) и "анимированный" при клике $('[href^="#"]').on('click', function(){ let href = $(this).attr('href'), elem = $(document).find(href); if(elem.length > 0) { let posY = elem.eq(0).offset().top; $('html, body').animate({ scrollTop: posY }, 1000); } return false; }); .list { display: block; width: 100%; height: 40px; background: gray; position: fixed; left: 0; top: 0; right: 0; padding: 0 10px; box-sizing: border-box; } .list > a { display: inline-block; height: 40px; line-height: 40px; color: #fff; text-decoration: none !important; } .list > a:not(:last-child) { margin-right: 5px; } .list > a:hover { color: red; } .item { display: block; width: 100%; height: 100vh; line-height: 100vh; text-align: center; font-size: 100px; }
Item 1
Item 2
Item 3
Item 4
Item 5
Плюсы Если после нажатия скопировать ссылку из адресной строки и перейти по ней, то "в поле зрения" будет тот самый блок, к которому был произведён "анимированный скролл". Минусы Использует JQuery (может и не минус для кого-то) Текущее положение находится "далеко" от того, к которому будет выполнен скролл, то "скролл" произойдёт быстро.

Ответ 2



$('.js-btn').click(() => { $('html, body').animate({ scrollTop: $('.js-section').offset().top }, 200); });

Ответ 3



Рекомендую использовать такой скрипт. В тег <а> Вы добавляете класс .following_scroll, а в href указываете id элемента к которому опуститься, в данном случае div с id="service" $('.flowing-scroll').on('click', function() { var el = $(this); var dest = el.attr('href'); // получаем направление if (dest !== undefined && dest !== '') { // проверяем существование $('html').animate({ scrollTop: $(dest).offset().top // прокручиваем страницу к требуемому элементу }, 500 // скорость прокрутки ); } return false; });


Ответ 4



var updownElem = document.getElementById('down'); var pageYLabel = 0; updownElem.onclick = function() { var pageY = window.pageYOffset || document.documentElement.scrollTop; switch (this.className) { case 'down': pageYLabel = pageY; window.scrollTo(0, 1000); this.className = 'down'; } } .button { cursor: pointer; text-align: center; display: block; width: 100px; margin: 0 auto; padding: 10px; background: blue; border: 2px solid pink; border-radius: 100px; color: white; }
JOIN
Привет!