Страницы

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

воскресенье, 1 декабря 2019 г.

Python скриптовый язык?

#python


Учительница по информатике сказала, что он скриптовый. Так ли это? Он же вроде компилируемый.
Мне 15, я не Senior разработчик, поэтому вопрос глупый. Я ведь даже на Python не пишу.
    


Ответы

Ответ 1



Под словом "скриптовый" чаще всего понимается понятие, близкое к "сценарию", то есть имеется в виду, что программа выполняется построчно сверху вниз. В IT-среде, как правило, произнося фразу "Я там небольшой скриптик написал для...", разработчик имеет в виду именно некий "сценарий" для автоматизации чего-либо. Питон для этой цели более чем подходит. Поэтому если тебя интересует просто ответ "да" или "нет", без досужих рассуждений, то да, скриптовый. P.S. Для ценителей - "скриптовый" == "интерпретируемый" НО в то же время "скриптовый" !== "интерпретируемый" :) если вы понимаете о чём я

Ответ 2



Python - интерпретируемый язык программирования. Исходный код выполняется непосредственно, команда за командой (иногда — с минимальной подготовкой, буквально после разбора исходного кода в AST),— программа просто не может быть запущена без наличия интерпретатора. В случае с самой распространенной реализацией (CPython: написанный на C, часто называемый просто “Python") ответ: интерпретируемый, с некоторой компиляцией. CPython компилирует исходный код на Питоне в байт код, а затем интерпретирует этот байткод, запуская его в процессе. Частично взято и дополнено отсюда Так же согласно Python - это интерпретируемый объектно-ориентированный язык программирования высокого уровня...

Ответ 3



Скорей всего учитель разделила языки на системные и сценарные. Первые чаще всего компилируются, вторые - интерпретируются. Среди сценарных можно выделить: командные языки - bash, powershell, прикладные - VBA, 1С (омг) и так называемые общего назначения/универсальные - python, javascript, perl, php, ruby. Если язык интерпретируемый, то при его запуске осуществляется мнговенное выполнение команд (строк) из вашего сценария. Порядок таков: прочитать инструкцию; проанализировать инструкцию и определить соответствующие действия; выполнить соответствующие действия; если не достигнуто условие завершения программы, прочитать следующую инструкцию и перейти к пункту 2. Такая реализация имеет и плюсы и минусы. Плюсы очень сильны, поэтому эти языки очень популярны.

Ответ 4



Это понятие относительное.Питон насколько я знаю конвертируется в байт код (.pyc ) ,а потом исполняется. Википедия: Python — высокоуровневый язык программирования общего назначения... Это вопрос "питон компилируется или интерпретируется или одновременно и то и то": "https://stackoverflow.com/questions/6889747/is-python-interpreted-or-compiled-or-both" Is python a scripting language? https://www.educba.com/python-scripting-language/ https://www.quora.com/Is-Python-a-programming-language-or-scripting-language https://stackoverflow.com/questions/46386442/python-is-language-or-script-language Wikipedia: Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum and first released in 1991, Python's design philosophy emphasizes code readability with its notable use of significant whitespace. Its language constructs and object-oriented approach aim to help programmers write clear, logical code for small and large-scale projects.

Как на сайте заблокировать F12?

#javascript #html #jquery #браузер


Как сделать так, чтобы при нажатии F12 на сайте не появлялось окно с исходным кодом?
    


Ответы

Ответ 1



Никак.

Ответ 2



Насчет кроссбраузерности не уверен, но в огнелисе работает. UPD. демо

Ответ 3



Ага. сначала F12, потом скажете нужно еще ctrl + u заблокировать, потом еще что-то.. Поэтому поддерживаю @ReinRaus. Проще сразу сказать заказчику что такое сделать нельзя! :)

Ответ 4



Ну так попробуй document.onkeypress = function (event) { event = (event || window.event); if (event.keyCode == 123) { //alert('No F-12'); return false; } } document.onmousedown = function (event) { event = (event || window.event); if (event.keyCode == 123) { //alert('No F-keys'); return false; } } document.onkeydown = function (event) { event = (event || window.event); if (event.keyCode == 123) { //alert('No F-keys'); return false; } } var message="Эх ты, мамке расскажу"; function clickIE() {if (document.all) {(message);return false;}} function clickNS(e) {if (document.layers||(document.getElementById&&!document.all)) { if (e.which==2||e.which==3) {(message);return false;}}} if (document.layers) {document.captureEvents(Event.MOUSEDOWN);document.onmousedown=clickNS;} else{document.onmouseup=clickNS;document.oncontextmenu=clickIE;} document.oncontextmenu=new Function("return false") function disableCtrlKeyCombination(e) { var forbiddenKeys = new Array('a', 'n', 'c', 'x', 'v', 'j' , 'w'); var key; var isCtrl; if(window.event) { key = window.event.keyCode; if(window.event.ctrlKey) isCtrl = true; else isCtrl = false; } else { key = e.which; if(e.ctrlKey) isCtrl = true; else isCtrl = false; } if(isCtrl) { for(i=0; i

Ответ 5



Добавьте еще одно такое же окно. Вроде и не блокировка, но озадачит противника. Для этого нужно попытаться отслеживать характерные изменения window.innerHeight, происходящие при открытии окна. P.S. И зачем это апнули 4 года спустя...

Методы сравнения ссылочных классов в .Net

#c_sharp #net #vbnet


Ранее считал, что переопределять Equals для своих классов можно и нужно. Но натолкнулся
на иную информацию, что переопределение может привести к проблемам с некоторыми коллекциями.


Когда следует переопределять object.Equals() для своих классов?
Неужели, если хочется сравнить на эквивалентность согласно сущности два объекта своих
классов, нужно создавать отдельный метод?
А как быть со сторонними классами? Получается они не поставляют средств сравнения
на эквивалентность сущностей?


Что я понимаю под эквивалентностью сущностей. Допустим есть класс 

public class Country
{ 
     public Country (string name)
     {
          this.name = name;
     }
     private readonly string name;
     public string Name { get {return name;}}
}

public void Main()
{
      var c1 = new Country("Россия");
      var c2 = new Country("Россия");
}


так вот c1 и с2 для меня эквивалентны, т.к. не может быть двух стран в моём мире,
с одинаковым названием. Просто так получилось, что мы создали два экземпляра, но они
идентичны по своей сути..
    


Ответы

Ответ 1



Как известно, .NET по умолчанию сравнивает объекты ссылочных типов по ссылкам, а объекты значимых типов -- побитово (читай, по значению). К чему это приводит в вашем примере? К тому, что c1 и c2 считаются неравными. С т.з. бизнес-логики вы правильно заметили, что они равны, однако среда ничего не знает о бизнес-логике. Отсюда выводы: Метод Equals() надо переопределять там, где требуется, чтобы объекты считались равными по какому-то определенному правилу. В частности, это нужно, когда вы используете объекты типа в качестве ключей словаря, элементов хэш-сета, а также в качестве элемента какой-либо коллекции и вызываете метод Contains(). Также стоит заметить, что в пару к Equals() нужно переопределять и метод GetHashCode(). Да, нужно. Потому что правила равенства двух объектов одного типа -- это, грубо говоря, бизнес-правила, то, что относится к вашему приложению. Среда исполнения о них ничего не знает, но о них знаете вы как разработчик. Для кастомного сравнения экземпляров сторонних классов используется интерфейс IEqualityComparer и его реализации. В BCL включены некоторые готовые реализации (например, для сравнения строк без учета регистра). В большинстве случаев вам потребуется создавать свой компаратор.

Ответ 2



Стоит переопределять object.Equals() в том случае, если для экземпляров вашего класса есть реально существующий метод определения эквивалентности, общий для всего кода приложения. При переопределении object.Equals() обязательно стоит переопределять и метод object.GetHashCode(), причем так, чтобы для эквивалентных объектов GetHashCode() возвращал одинаковое значение. Нет, переопределение object.Equals() - не единственный доступный метод. Если нужно задать определение эквивалентности в одном конкретном случае, а не по всему приложению - то можно использовать стороннее сравнение через реализацию IEqualityComparer. Почти все стандартные коллекции позволяют использовать IEqualityComparer - либо как параметр конкретного метода поиска, или как параметр конструктора коллекции. Для сторонних классов - см. 2.

Ошибка “variable might not have been initialized”

#java #компиляция


Возник вопрос по логике кода. Почему компилятор не пропускает такой код?

String testStr;
if (check > 0) {
  testStr = "abc";
}
System.out.println(testStr != null ? testStr: "0");


При компиляции выдаётся ошибка:


  Error:(134, 32) java: ... variable testStr might not have been initialized


Хотя вроде как логичным будет просто вывести "0" в случае, если testStr не было инициализировано...
Какая тут логика?
    


Ответы

Ответ 1



Есть два варианта интерпретации данного кода: Программист хотел объявить переменную с каким-то значением, но допустил ошибку в коде: пропустил присвоение значения либо блок else. В этом случае компилятор поможет ему найти ошибку. Программист полагает, что testStr будет инициализировано как null по умолчанию. В этом случае компилятор заставит программиста инициализировать переменную как null явно. Разработчики Java пришли к выводу, что: важно отловить возможные ошибки; неудобства, связанные с инициализацией локальных переменных, незначительны. Обязательная инициализация локальных переменных определена в спецификации Java: Chapter 16. Definite Assignment Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs. An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by this) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator = (§15.26.1). For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs. Перевод (из книги «Язык программирования Java SE 8. Подробное описание») Глава 16. Определенное присваивание Каждая локальная переменная (§14.4) и каждое пустое final-поле (§4.12.4, §8.3.1.2) должны иметь определенно присвоенное значение при любом обращении к их значениям. Обращение к их значениям состоит из простого имени переменной (или, в случае поля, простого имени поля, квалифицированного ключевым словом this), находящегося в любом месте выражения, за исключением левого операнда оператора присваивания = (§15.26.1). Для каждого обращения к локальной переменной или к пустому final-полю x, x должно быть определенно присвоено до этого обращения, иначе генерируется ошибка времени компиляции. Посмотрите также обсуждения этого вопроса в английской версии: Why are local variables not initialized in Java? Why must local variables, including primitives, always be initialized in Java?

Ответ 2



В Java локальные переменные не имеют значения по умолчанию. Это означает что при простом объявлении переменной у неё не будет значения. В приведённом коде при check<=0 переменная так и останется не инициализированной при обращении к ней, на что и ругается компилятор. String testStr=null; Это решит проблему

Анимация персонажа прыгающей девочки

#html #css #css3 #svg #анимация


На просторах интернета нашел гифку  прыгающей девочки:

 

Возник вопрос,- как реализовать эту анимацию с помощью CSS или SVG? 

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


Ответы

Ответ 1



Рисуем или находим готовый спрайт: Ширина спрайта - 640px Ширина одного кадра будет задана - 160px Спрайт добавляется в качестве фона и будет дискретно, по кадру перемещаться в окне равному по ширине и высоте одному кадру: width: 160px; и height: 276px; команда анимации перемещения: animation: run 0.5s steps(4) infinite; Осталось подобрать подходящий музыкальный фрагмент: "Boney M - Happy Song" body { background-image:url(https://i.stack.imgur.com/0f4Hg.jpg); background-size:cover; } .girl { animation: run 0.5s steps(4) infinite; -webkit-animation: run 0.5s steps(4) infinite; background: url(https://i.stack.imgur.com/B9kwD.png) 0 100%; background-repeat: no-repeat; position: absolute; bottom:0; right:50%; width: 160px; height: 276px; } @keyframes run { from { background-position: 0px; } to { background-position: -612px; } } .play-audio { position:absolute; bottom:0%; }
Update 18.03.2019 г. Chrome запретил автоматический запуск mp3 поэтому добавил аудиоплейер. Добавлена фоновая картинка дворика.

Ответ 2



Ответ разумеется не по теме, но тут так же анимация но на чистом css - очень эффектно выглядит body { background: #fff; height: 100vh; overflow: hidden; display: -webkit-box; display: -ms-flexbox; display: flex; font-family: 'Anton', sans-serif; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; -webkit-perspective: 500px; perspective: 500px; } div { position: absolute; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; } .paper_man_wrapper { -webkit-animation: cameraY 7000ms linear infinite; animation: cameraY 7000ms linear infinite; } .paper_man { top: -100px; left: -50px; -webkit-animation: cameraX 5000ms ease-in-out infinite alternate; animation: cameraX 5000ms ease-in-out infinite alternate; } .paper_man .part { background: black; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .paper_man .part::before { content: ''; position: absolute; width: 100%; height: 100%; background: #646464; -webkit-transform: rotateY(180deg); transform: rotateY(180deg); -webkit-backface-visibility: hidden; backface-visibility: hidden; } .paper_man_body { -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-transform: rotateX(-20deg); transform: rotateX(-20deg); width: 60px; height: 100px; -webkit-animation: shake4 2000ms -100ms ease-in-out infinite; animation: shake4 2000ms -100ms ease-in-out infinite; } .paper_man_head { -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; top: -40px; left: calc(50% - 20px); width: 40px; height: 40px; -webkit-transform: rotateX(-10deg); transform: rotateX(-10deg); -webkit-animation: shake4 1000ms -800ms ease-in-out infinite; animation: shake4 1000ms -800ms ease-in-out infinite; } .paper_man_arm.left { -webkit-transform-origin: 0 0; transform-origin: 0 0; right: 0px; -webkit-animation: shake1 1000ms -400ms ease-in-out infinite; animation: shake1 1000ms -400ms ease-in-out infinite; } .paper_man_arm.right { -webkit-transform-origin: 100% 0; transform-origin: 100% 0; left: -20px; -webkit-animation: shake1 1000ms -900ms ease-in-out infinite; animation: shake1 1000ms -900ms ease-in-out infinite; } .paper_man_arm_1 { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; width: 20px; height: 50px; } .paper_man_arm_2 { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; bottom: -50px; width: 20px; height: 50px; } .left .paper_man_arm_2 { -webkit-animation: shake3 1000ms -800ms ease-in-out infinite; animation: shake3 1000ms -800ms ease-in-out infinite; } .right .paper_man_arm_2 { -webkit-animation: shake3 1000ms -300ms ease-in-out infinite; animation: shake3 1000ms -300ms ease-in-out infinite; } .paper_man_arm_hand { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; bottom: -15px; width: 20px; height: 15px; } .left .paper_man_arm_hand { -webkit-animation: shake3 1000ms -200ms ease-in-out infinite; animation: shake3 1000ms -200ms ease-in-out infinite; } .right .paper_man_arm_hand { -webkit-animation: shake3 1000ms -700ms ease-in-out infinite; animation: shake3 1000ms -700ms ease-in-out infinite; } .paper_man_leg { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; top: 100px; } .paper_man_leg.left { right: 30px; -webkit-animation: shake1 1000ms ease-in-out infinite; animation: shake1 1000ms ease-in-out infinite; } .paper_man_leg.right { left: 0; -webkit-animation: shake1 1000ms -500ms ease-in-out infinite; animation: shake1 1000ms -500ms ease-in-out infinite; } .paper_man_leg_1 { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; width: 30px; height: 50px; } .paper_man_leg_2 { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; bottom: -40px; width: 30px; height: 40px; } .left .paper_man_leg_2 { -webkit-animation: shake2 1000ms -600ms ease-in-out infinite; animation: shake2 1000ms -600ms ease-in-out infinite; } .right .paper_man_leg_2 { -webkit-animation: shake2 1000ms -100ms ease-in-out infinite; animation: shake2 1000ms -100ms ease-in-out infinite; } .paper_man_leg_foot { -webkit-transform-origin: 50% 0; transform-origin: 50% 0; bottom: -20px; width: 30px; height: 20px; } .left .paper_man_leg_foot { -webkit-animation: shake3 1000ms -400ms ease-in-out infinite; animation: shake3 1000ms -400ms ease-in-out infinite; } .right .paper_man_leg_foot { -webkit-animation: shake3 1000ms -900ms ease-in-out infinite; animation: shake3 1000ms -900ms ease-in-out infinite; } @-webkit-keyframes shake1 { 0% { -webkit-transform: rotateX(80deg); transform: rotateX(80deg); } 50% { -webkit-transform: rotateX(-80deg); transform: rotateX(-80deg); } 100% { -webkit-transform: rotateX(80deg); transform: rotateX(80deg); } } @keyframes shake1 { 0% { -webkit-transform: rotateX(80deg); transform: rotateX(80deg); } 50% { -webkit-transform: rotateX(-80deg); transform: rotateX(-80deg); } 100% { -webkit-transform: rotateX(80deg); transform: rotateX(80deg); } } @-webkit-keyframes shake2 { 0% { -webkit-transform: rotateX(0deg); transform: rotateX(0deg); } 50% { -webkit-transform: rotateX(-100deg); transform: rotateX(-100deg); } 100% { -webkit-transform: rotateX(0deg); transform: rotateX(0deg); } } @keyframes shake2 { 0% { -webkit-transform: rotateX(0deg); transform: rotateX(0deg); } 50% { -webkit-transform: rotateX(-100deg); transform: rotateX(-100deg); } 100% { -webkit-transform: rotateX(0deg); transform: rotateX(0deg); } } @-webkit-keyframes shake3 { 0% { -webkit-transform: rotateX(10deg); transform: rotateX(10deg); } 50% { -webkit-transform: rotateX(120deg); transform: rotateX(120deg); } 100% { -webkit-transform: rotateX(10deg); transform: rotateX(10deg); } } @keyframes shake3 { 0% { -webkit-transform: rotateX(10deg); transform: rotateX(10deg); } 50% { -webkit-transform: rotateX(120deg); transform: rotateX(120deg); } 100% { -webkit-transform: rotateX(10deg); transform: rotateX(10deg); } } @-webkit-keyframes shake4 { 0% { -webkit-transform: rotateX(-30deg); transform: rotateX(-30deg); } 50% { -webkit-transform: rotateX(-10deg); transform: rotateX(-10deg); } 100% { -webkit-transform: rotateX(-30deg); transform: rotateX(-30deg); } } @keyframes shake4 { 0% { -webkit-transform: rotateX(-30deg); transform: rotateX(-30deg); } 50% { -webkit-transform: rotateX(-10deg); transform: rotateX(-10deg); } 100% { -webkit-transform: rotateX(-30deg); transform: rotateX(-30deg); } } @-webkit-keyframes cameraY { 0% { -webkit-transform: rotateY(0deg); transform: rotateY(0deg); } 100% { -webkit-transform: rotateY(360deg); transform: rotateY(360deg); } } @keyframes cameraY { 0% { -webkit-transform: rotateY(0deg); transform: rotateY(0deg); } 100% { -webkit-transform: rotateY(360deg); transform: rotateY(360deg); } } @-webkit-keyframes cameraX { 0% { -webkit-transform: rotateX(-50deg); transform: rotateX(-50deg); } 100% { -webkit-transform: rotateX(50deg); transform: rotateX(50deg); } } @keyframes cameraX { 0% { -webkit-transform: rotateX(-50deg); transform: rotateX(-50deg); } 100% { -webkit-transform: rotateX(50deg); transform: rotateX(50deg); } }
Источник: Yusuke Nakaya

Как будет работать GC

#java #сборщик_мусора


Рассмотрим случай, когда объект хранит ссылку на самого себя. Ну например что-то
вроде такого

public class A {

   private A a;

   public A() {
      a = this;
   }
}


Каким в данном случае будет жизненный цикл объектов данного класса? GC не трогает
объекты до тех пор, пока есть ссылки на них. Следует ли из этого то, что объекты этого
класса как минимум будут храниться в памяти до тех пор, пока я не присвою переменной
a значение null?
    


Ответы

Ответ 1



Объекты не удаляются до тех пор пока они "достижимы" (доступны по ссылкам) от так называемого "корня" (GC root). Ссылки не достижимые от корня в том числе и циклические ссылки не являются препятствием для сборки мусора. В зависимости от варианта используемого алгоритма сборки мусора, есть различия в том, какие стадии сборки и в какой момент запускаются и по какому признаку объекты разделены на так называемые "поколения"(generations), однако упрощенная схема сборки примерно одна для большинства сборщиков: Объекты помечаются как достижимые (MARK) GC кушает недостижимые объекты (SWEEP) Визуализация примерной схемы работы алгоритма Garbage Collector использующего алгоритм из подмножества Mark-Sweep

Получить доступ к папке

#c_sharp #net #файловая_система


Нужно получить права на чтение и запись залоченого фолдера.

Или как сделать следующий код валидным:

        DirectoryInfo dir = new DirectoryInfo(@"D:/System Volume Information");

        foreach (var item in dir.GetDirectories())
        {
            Console.WriteLine(item.FullName);
        }


Желательно что бы работало с System Volume Information

Следующий код не работает тоже:

    [Flags]
    enum MoveFileFlags
    {
        MOVEFILE_REPLACE_EXISTING = 0x00000001,
        MOVEFILE_COPY_ALLOWED = 0x00000002,
        MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004,
        MOVEFILE_WRITE_THROUGH = 0x00000008,
        MOVEFILE_CREATE_HARDLINK = 0x00000010,
        MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
    }

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName,
MoveFileFlags dwFlags);

    static void Main(string[] args)
    {
        string path = @"D:/System Volume Information";

        DirectoryInfo dir = new DirectoryInfo(path);

        MoveFileEx(path, path + "2", MoveFileFlags.MOVEFILE_REPLACE_EXISTING);

        string msg = new Win32Exception(Marshal.GetLastWin32Error()).Message;

        Console.WriteLine(msg);
    }

    


Ответы

Ответ 1



Ага, я нашёл, как Far это делает. Он не просто запускает процесс от имени администратора (на самом деле, дочерний процесс, с которым связывается через pipe). Этот самый дочерний процесс, будучи запущенным от имени администратора, имеет право затребовать себе привилегии Backup и Restore (вот официальный метод, как сделать такое на чистом WinAPI). Что он и делает. Имея эти привилегии, дочерний процесс может делать всё. Мораль: вы можете ограничить в правах административный процесс, но он может снять ваши ограничения. Для читателей, вот работающий код: (разумеется, вы должны добавить манифест, как указано в ответе @Dmitry) class Program { static public void Main() { using (var outf = File.CreateText(@"D:\dirlist.txt")) { if (!RequestSeBackupPrivilege()) { outf.WriteLine("Cannot request privilege: "); return; } try { string path = @"D:\System Volume Information"; var dir = new DirectoryInfo(path); foreach (var item in dir.GetFileSystemInfos()) outf.WriteLine(item.FullName); } catch (Exception ex) { outf.WriteLine("Exception:"); outf.Write(ex); } } } static bool RequestSeBackupPrivilege() { LUID luid; if (!LookupPrivilegeValue(null, "SeBackupPrivilege", out luid)) return false; TOKEN_PRIVILEGES_SINGLE tp = new TOKEN_PRIVILEGES_SINGLE { PrivilegeCount = 1, Luid = luid, Attributes = SE_PRIVILEGE_ENABLED }; IntPtr hToken; return OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken) && AdjustTokenPrivileges( hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero) && (Marshal.GetLastWin32Error() != ERROR_NOT_ALL_ASSIGNED); } const int SE_PRIVILEGE_ENABLED = 0x00000002; const int TOKEN_QUERY = 0x00000008; const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; const int ERROR_NOT_ALL_ASSIGNED = 1300; [DllImport("kernel32.dll", ExactSpelling = true)] static extern IntPtr GetCurrentProcess(); [StructLayout(LayoutKind.Sequential)] struct TOKEN_PRIVILEGES_SINGLE { public UInt32 PrivilegeCount; public LUID Luid; public UInt32 Attributes; } [StructLayout(LayoutKind.Sequential)] struct LUID { public uint LowPart; public int HighPart; } [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool LookupPrivilegeValue( string lpSystemName, string lpName, out LUID lpLuid); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool OpenProcessToken( IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] static extern bool AdjustTokenPrivileges( IntPtr htok, bool disall, ref TOKEN_PRIVILEGES_SINGLE newst, int len, IntPtr prev, IntPtr relen); } Определения структур данных взяты на pinvoke.net.

Ответ 2



Насколько я помню, этот фолдер не залочен, а требует повышенных привилегий администратора. Чтобы повысить привилегии вашего приложения, добавьте в проект файл манифеста (выполнив Project -> Add New Item -> "Application Manifest File"), а в нем откорректируйте значение узла requestedExecutionLevel следующим образом:

Ответ 3



VladD прав. Это защищенная системная папка, доступ к которой осуществляется при помощи прав Local System. Вам нужно запустить свое приложение от Local System, сделать это можно следующими способами: Использовать планировщик задач (TaskScheduler). Написать службу и запустить приложение из нее. Внедриться в какой-нибудь LocalSystem-процесс и оттуда запустить свою программу. Использовать psexec (Sysinternals) с ключом -s.

Загрузка нового apk приложения - ошибка номера версии

#android #google_play


Здравствуйте! При загрузке новой версии приложения в Google Play возникает ошибка
такого вида:
APK-файл с кодом версии 1 уже существует. Используйте другой код.
Вопрос заключается в том, где и как можно заменить этот самый код?
    


Ответы

Ответ 1



Update в build.gradle(Module: app) android { ... defaultConfig { ... versionCode 2 //для Google Play versionName "1.1" //для пользователей } } в manifest Вашего проекта

Ответ 2



Чтобы Google Play принял новую версию приложения, нужно повысить версию кода android:versionCode. Если ранее android:versionCode="1", то в новой версии он должен быть на 1 больше - android:versionCode="2". Если Вы пишете приложения в среде разработки Android Studio С применением Gradle системы сборки, то версию кода нужно будет повышать в файле build.gradle уровня приложения, то есть того, что лежит в папке /app. Внутри этого файла Вы легко найдете строчку versionCode. versionName - Ваша собственная версия приложения, ее можно показывать пользователям. Она может быть двойная, тройная, с буквами. На Википедии подробнее об этом - Нумерация версий программного обеспечения После этого нужно собрать *.apk через Build-Generate signed APK.... Успехов!

Ответ 3



Если работаете в Android Studio, то зайдите в структуру проекта - кнопка на панели инструментов или File / Project Structure... или сочетание клавиш Ctrl + Alt + Shift + S. Заходите в настройки вашего приложения Modules / app, вкладка Flavors. Там меняете код версии (+ 1) и название версии (при необходимости). Для публикации обновления в Google Play достаточно изменить только код версии.

Что означает доллар?

#jquery #jquery_ui


Здравствуйте. Не могу понять, что означает эта запись на jQuery:
var $tab_title_input = $( "#tab_title"),

Насколько я знаю, знак доллара обычно обозначает какую-то функцию (или слово jQuery).
Что этим хотели сказать разработчики? Пример взят с офсайта jQuery.    


Ответы

Ответ 1



Знак доллара является разрешенным символов для идентификатора в языке Javascript. jQuery использует знак $ как псевдоним (сокращение) для идентификтора jQuery. То есть в данном конкретном случае $tab_title_input - просто имя, включающее знак доллара, $( "#tab_title") - вызов функции jQuery.

Ответ 2



Нашел в одной статье, думаю это будет полезно к сведению. Венгерская нотация (Советы: как писать качественный код на jQuery) Если говорить простыми словами, венгерская нотация1 в jQuery — это когда в начале переменной стоит символ доллара, и вам легко сразу понять, что эта переменная содержит jQuery-объект. // плохо var first = $('#first'); var second = $('#second'); var value = $first.val(); // хорошо - перед объектами, которые управляются jQuery, мы ставим символ $ var $first = $('#first'); var $second = $('#second'), var value = $first.val();

Ответ 3



function $(id) { return document.getElementById(id); } $("mydiv").onclick = function() { //some actions } К примеру когда я обращаюсь к DOM элементам используя функцию выше, я хочу сказатать что использовать знак $ для меня просто удобно! Я не сторонник Jquery, и свои велосипеды тоже умеют ездить!

Ответ 4



$ у переменной значит, что это объект jQuery

Ответ 5



Инициализация (то бишь она же идентификация, обозначение что это jQuery дабы не вызывать конфликтов)jQuery. P.S. Не объект, не закос под пшп, это инициализация! Так же может использоваться как простой символ в имени переменной, либо как вызов функции.

Парсинг сайта в java с помощью jsoup

#java #парсер #jsoup


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


Ответы

Ответ 1



Ну, а в чём проблема? Загрузите документ. Снавигируйте к элементу, содержащему программы. Тем же способом найдите нужные элементы данных. Какие именно HTML-атрибуты вам нужны, устанавливается внимательным чтением исходника сайта, который вы собираетесь распарсить. На сайте даже есть простейший пример (без навигации, просто все ссылки).

Ответ 2



Есть 2 типа html/xml парсеров: SAX парсер - парсит в потоковом режиме, на вход подается поток html/xml, в определенных местах срабатывают т.н. хэндлеры, то есть перехватчики, которые говорят "сейчас парсер наткнулся на такой-то элемент". В хэндлер обычно прогер вставляет свой код и делает свое дело DOM парсер - засовывается весь источник, на выходе получаем дерево - иногда довольно сложное. jsoup это разновидность DOM парсера, так что весь вопрос в том, чтобы правильно спозиционироваться в дереве полученном после парсинга - или выражаясь языком модели DOM в нодах. Это описываетс документацией jsoup API в пакете org.jsoup.nodes. Заодно нелишним будет почитать про DOM это сразу направит мозги в нужном направлении. Удачи.

Ответ 3



Я это делаю так. Тоже первый раз :) Пока не разобрался как красиво выводить то, что спарсил :( package sm.play.sportlife.ua; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); public static int dayOfTheWeek = 0; // благодоря этому классу мы будет разбирать данные на куски public Elements time, currentday; // то в чем будем хранить данные public ArrayList timeList = new ArrayList(); public ArrayList dayEventList = new ArrayList(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** Запрос к нашему отдельному поток на выборку данных */ new GetDataThread().execute(); dayOfTheWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1; if (dayOfTheWeek == 0) { dayOfTheWeek = 7; } Log.d(TAG, "День недели :" + dayOfTheWeek); } /** * А вот и внутрений класс который делает запросы в отдельном потоке */ public class GetDataThread extends AsyncTask { private TableRow row; private TableLayout inflate; private TextView txtcol1, txtcol2; private String eventNames; // private ProgressDialog prog; /** * Метод выполняющий запрос в фоне, в версиях выше 4 андроида, запросы в * главном потоке выполнять нельзя, поэтому все что вам нужно выполнять * - выносите в отдельный поток */ @Override protected String doInBackground(String... arg) { String myURL = "http://www.sportlife.ua/ru/services/schedule/14875"; // класс который захватывает страницу Document doc; try { // определяем откуда будем скачивать данные doc = Jsoup .connect(myURL) .userAgent( "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36") .get(); // задаем с какого места парсить /** * Выбираем содержимое рассписания по индексу столбца * td:eq(Индекс) */ // Время занятий int k = 0; String link = "#shedule-content tr:gt(0) " + "td:eq(" + k + ")"; time = doc.select(link); link = "#shedule-content tr:gt(0) " + "td:eq(" + dayOfTheWeek + ")"; currentday = doc.select(link); /** * Чистим наши ArrayList для того что бы заполнить и в цикле * захватываем все данные какие есть на странице */ timeList.clear(); dayEventList.clear(); for (Element times : time) { if (times.className().equals("time-col")) { timeList.add(times.text()); // Записываем в ArrayList // время занятий } } /** * Для каждого event currentday из записываем в аррей лист * события дня */ for (Element event : currentday) { if (event.hasText() == true) { Elements mEvents = Jsoup.parse(event.html()).select( ".event-item-body"); /** Может быть несколько занятий на одно и тоже время */ int i = 0; do { Element textEvent = mEvents.get(i); String tmpString = textEvent.text(); if (eventNames == null) { eventNames = tmpString + "\n"; } else { eventNames = eventNames + tmpString + "\n"; } i++; } while (i < mEvents.size()); /** События заносим в список */ dayEventList.add(eventNames); eventNames = ""; } else // dayEventList.add(titles.text()); dayEventList.add(""); } } catch (IOException e) { e.printStackTrace(); } return null; } @Override protected void onPreExecute() { // prog = new ProgressDialog(MainActivity.this); // prog.setMessage("Соединяемся..."); // prog.show(); } @Override protected void onPostExecute(String result) { /** ФОРМИРУЕМ ТАБЛИЦУ */ inflate = (TableLayout) MainActivity.this .findViewById(R.id.mytable); for (int i = 0, j = 0; i < timeList.size() || j < dayEventList.size();) { row = new TableRow(MainActivity.this); txtcol1 = new TextView(MainActivity.this); if (timeList.size() > i) { if ((timeList.get(i) != null)) { txtcol1.setText(timeList.get(i)); txtcol1.setBackgroundResource(R.drawable.shape_rec); // txtcol1.setTextColor(Color.rgb(245, 245, 220)); // txtcol1.setBackgroundColor(Color.rgb(0, 0, 0)); i++; } } else { txtcol1.setText(""); } row.addView(txtcol1); txtcol2 = new TextView(MainActivity.this); if ((dayEventList.size() > j)) { if (dayEventList.get(j) != null) { txtcol2.setText(dayEventList.get(j)); txtcol2.setBackgroundResource(R.drawable.shape_rec); // txtcol2.setMaxLines(20); j++; } } else { txtcol2.setText(""); } this.row.addView(txtcol2); inflate.addView(row); } /** КОНЕЦ ФОРМИРОВАНИЯ ТАБЛИЦЫ */ // super.onPostExecute(result); // prog.dismiss(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment { public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; } } }

Сортировка map по значению java

#java


Есть map, как ее отсортировать по значению?    


Ответы

Ответ 1



Map map = new HashMap<>(); List list = new ArrayList(map.entrySet()); Collections.sort(list, new Comparator>() { @Override public int compare(Map.Entry a, Map.Entry b) { return a.getValue() - b.getValue(); } }); Исправил

Ответ 2



java 8 import java.util.Map; import java.util.HashMap; public class Main { public static void main(String[] args) { HashMap map = new HashMap(); map.put(1, 10); map.put(2, 30); map.put(3, 50); map.put(4, 40); map.put(5, 100); map.put(6, 60); map.put(7, 110); map.put(8, 50); map.put(9, 90); map.put(10, 70); map.put(11, 80); map.entrySet().stream() .sorted(Map.Entry.comparingByValue().reversed()) .forEach(System.out::println); // или любой другой конечный метод } } Вывод: 7=110 5=100 9=90 11=80 10=70 6=60 3=50 8=50 4=40 2=30 1=10

Ответ 3



Сходу написать такой сортировщик не так просто. По крайней мере, я для себя выбрал в этом случае такую стратегию: раз написал, много раз используй. Поэтому такой сортировщик я написал через Generics т.к. в map может иметь и другие типы в качестве ключа и значения. Ниже я поделюсь двумя версиями сортировочного метода. Для Java version = 7 и для Java version = 8. Итак, если у Вас 7-я версия Java: public static > Map sortByValue(Map map ) { List> list = new LinkedList<>(map.entrySet()); Collections.sort( list, new Comparator>() { @Override public int compare(Map.Entry o1, Map.Entry o2) { return (o1.getValue()).compareTo( o2.getValue() ); } } ); Map result = new LinkedHashMap<>(); for (Map.Entry entry : list) { result.put(entry.getKey(), entry.getValue()); } return result; } Т.е., сначала, как писал @Nofate, вытаскиваем список entries (это у нас переменная list), затем сортируем эти entries по значениям и заливаем в новую мапу (это у нас result). Для результирующей мапы я использовал LinkedHashMap чтобы при добавлении элементы не пересортировывались. А вот версия с использованием Stream'ов из Java 8: public static > Map sortByValue( Map map ) { Map result = new LinkedHashMap<>(); Stream > st = map.entrySet().stream(); st.sorted(Comparator.comparing(e -> e.getValue())) .forEach(e ->result.put(e.getKey(),e.getValue())); return result; }

Ответ 4



Делаем два ArrayList-а с ключом и значением. Парсим HashMap, сразу сортируя по значению. ArrayList strings = new ArrayList<>(); ArrayList floats = new ArrayList<>(); for (HashMap.Entry e : map.entrySet()) { float value = e.getValue(); boolean isAdded = false; for (int i = 0; i < floats.size(); i++) { if (value > floats.get(i)) { floats.add(i, value); strings.add(i, e.getKey()); isAdded = true; break; } } if (!isAdded) { floats.add(value); strings.add(e.getKey()); } } for (int i = 0; i < strings.size(); i++) { Log.d(TAG, "sort: " + strings.get(i) + "=" + floats.get(i)); } На выходе отсортированные ArrayList-ы.

Ответ 5



TreeMap< String ,Integer> map= new TreeMap< String,Integer>(); SortedMap sortMapa = new TreeMap(new IntegerComparator()); Iterator it = map.entrySet().iterator(); while(it.hasNext()) { @SuppressWarnings("unchecked") Entry< String ,Integer> En = (Entry) it.next(); sortMapa.put( En.getValue(), En.getKey()); } Iterator sortit = sortMapa.entrySet().iterator(); while(sortit.hasNext()) { @SuppressWarnings("unchecked") Entry< Integer,String > sEn = (Entry) sortit.next(); System.out.println(sEn.getValue()+"-->"+sEn.getKey()); }

Как разрешается конфликт изменений при слиянии ветвей?

#git #git_merge


Диспозиция такая:

Есть две ветки. в каждой из них присутствует файл который редактировался (один и тот же).

При слиянии веток что произойдет с этим файлом?
    


Ответы

Ответ 1



Если кратко: произойдет конфликт слияния (merge conflict) и его нужно будет как-то разрешить. Для бинарных файлов: только выбрать версию А или Б (или другие, если octomerge). Бывает, что бинарные файлы Git воспринимает как текстовые и тогда merge их необратимо портит. Это прежде всего относится к файлам office-форматов. Для текстовых файлов: пара вариантов: Вручную разрешить конфликты После merge в файле появятся куски из обеих сливаемых версий, как-то так: <<<<<<< HEAD содержимое файла из первой ветки ====== содержимое файла из второй ветки >>>>>>> otherbranch Нужно будет вручную отредактировать конфликтный файл (или файлы), при этом не забывая удалить метки, оставленные Git (>>>>>>> otherbranch). Затем: git add conflicting-file-name.txt git commit -m'merged A and B' Выбрать одну из версий файла Можно явным образом указать: какой файл выбирать. Подходит, только если одна из версий не нужна. git checkout --ours a.txt git checkout --theirs a.txt git add a.txt git commit -m "added theirs" Сделал вам тестовый репозиторий, чтобы сразу клонировать и посмотреть, как оно работает. git clone https://github.com/NickVolynkin/git-merge-test.git cd git-merge-test git merge otherbranch open a.txt В файле видны отметки, можете с ним теперь проделать вышеописанные действия. Подробнее написано в книге Pro Git на русском. Ее обязательно нужно прочитать, прежде чем работать со слиянием веток. Фундаментальное понимание процесса ничем не заменить. Потренироваться с ветвлением и слиянием можно тут: Learn Git Branching.

Ответ 2



проблемы с мерджем могут возникнуть из-за использования неудобного редактора. Попробуйте сменить Ваш консольный редактор на IDE или специализированный софт для этих нужд https://git-scm.com/download/gui/linux Nick Volynkin теорию скинул

Массив функций: можно ли реализовать?

#cpp #массивы


Можно ли в C++ реализовать массив функций? То есть, в массив можно записать функции
a(), b() и c() (не сами функции, а операторы для их вызова), а затем вызывать их, как
будет удобно. Если нет, то можно вызывать ту функцию, которая указана в аргументах?
    


Ответы

Ответ 1



В современном c++ присутствуют удобные средства для оперирования функциями как функциональными объектами. Посмотрите functional, а именно std::function и std::bind. По указанным ссылкам также находятся очень хорошие примеры. Разумеется в c++ можно работать и с голыми указателями на функции (свободные и функции-члены класса), но это не так удобно и просто. Особенно при построении пользовательского интерфейса. Пример массива функций. В качестве массива используем стандартный контейнер std::vector. Ниже продемонстрировано как можно для более узкой сигнатуры функции использовать более широкое определение. Известно что вызывающая сторона ожидает сигнатуру void(int), а мы будем ей передавать void(int, int) и void(const std::string&, int, int). #include // std::cout #include // std::bind #include #include void a(int x, int y) { std::cout << "a(" << x << ", " << y << ")" << std::endl; } void b(int x, int y) { std::cout << "b(" << x << ", " << y << ")" << std::endl; } void c(const std::string& s, int x, int y) { std::cout << "c(" << s << ", " << x << ", " << y << ")" << std::endl; } int main () { using namespace std::placeholders; // adds visibility of _1, _2, _3,... std::vector> functions; // создаем и помещаем в вектор функциональный объект, во время вызова необходимо передать один аргумент functions.emplace_back(std::bind(a, _1, _1)); functions.emplace_back(std::bind(a, _1, 42)); functions.emplace_back(std::bind(a, _1, 100500)); functions.emplace_back(std::bind(b, _1, 42)); functions.emplace_back(std::bind(b, 42, _1)); functions.emplace_back(std::bind(c, "Hello world!", _1, 3)); int i = 0; for (const auto& fn : functions) { fn(i++); } return 0; } Вывод. a(0, 0) a(1, 42) a(2, 100500) b(3, 42) b(42, 4) c(Hello world!, 5, 3) Еще один пример (взят с www.cplusplus.com): // bind example #include // std::cout #include // std::bind // a function: (also works with function object: std::divides my_divide;) double my_divide (double x, double y) {return x/y;} struct MyPair { double a,b; double multiply() {return a*b;} }; int main () { using namespace std::placeholders; // adds visibility of _1, _2, _3,... // binding functions: auto fn_five = std::bind (my_divide,10,2); // returns 10/2 std::cout << fn_five() << '\n'; // 5 auto fn_half = std::bind (my_divide,_1,2); // returns x/2 std::cout << fn_half(10) << '\n'; // 5 auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x std::cout << fn_invert(10,2) << '\n'; // 0.2 auto fn_rounding = std::bind (my_divide,_1,_2); // returns int(x/y) std::cout << fn_rounding(10,3) << '\n'; // 3 MyPair ten_two {10,2}; // binding members: auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply() std::cout << bound_member_fn(ten_two) << '\n'; // 20 auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a std::cout << bound_member_data() << '\n'; // 10 return 0; }

Ответ 2



Конечно можно! double (*funcs_array[64])(int a, float b); Однако обычно, чтобы не запутаться, я объявляю тип указателя на функцию отдельным псевдонимом. Тогда объявление массива таких указателей не отличается от объявления массива либого другого типа. typedef double (*FuncPtr)(int a, float b); FuncPtr funcs_array[64]; Про указатели на функции неплохой стартовый пост был у Алены.

Ответ 3



Имя функции в Си++ - это такой же указатель как и все прочие. Соответственно можно собрать их в массив. Главное с аргументами не перемудрить

Ответ 4



Конечно можно создавать массивы функций и вызывать их из массива. Посмотрите мой код с комментариями как это делается. #include using namespace std; // Создаем три функции с одинаковым количеством параметров // и соответствующими типами, а так же возращаемым типом int sum(const int a, const int b){ return a + b; } int sep(const int a, const int b){ return a - b; } int mul(const int a, const int b){ return a * b; } typedef // создаем новый прототип (в данном случае указатель на функцию) int // возвращаемое значение (такое же как в функциях) (*func) // имя прототипа (в коде употребляется без звездочки) (const int, const int); // список параметров (такое же как в функциях) int main(){ func arr[3]; // обьявляем массив функций из трех элементов // помещаем в массив функции указывая их имена (потому что имя функции это и есть указатель на нее) arr[0] = sum; arr[1] = sep; arr[2] = mul; // используем указатели из массива (выводим результат функций в массиве с конкретными параметрами) cout << arr[0](5, 2) << endl; cout << arr[1](5, 2) << endl; cout << arr[2](5, 2) << endl; return 0; }

Как настроить подключение к удаленному Git репозиторию

#git #ssh #git_remote


Как настроить подключение к удаленному Git-репозиторию, через SSH, на компьютере
с Windows 7 . И соответственно выкачать содержимое к себе на локальный сервер. 

Удаленный репозиторий находится на сервере с git. мне нужно просто склонировать содержимое.
никаких пушей обратно. там есть идентификация. сгенерил паблик кей и отослал спец-ту
на той стороне. как мне добавить ранее сгенеренный-свой ключ через консоль и подключиться
к серверу? какие команды..? Windows 7 на моей машине. 
    


Ответы

Ответ 1



Установка Если ещё не установлен, то Git можно взять здесь. Вместе с ним будет unix-like консоль Git Bash. https://github.com/git-for-windows/git/releases/ Клонирование через SSH Пример команды для клонирования через SSH. git clone git@github.com:brockgr/csshx.git В общем случае команда для клонирования по SSH выглядит так: git clone git@server.domain:user/reponame.git Не перепутайте с HTTPS, который потребует авторизации через логин-пароль: git clone https://github.com/brockgr/csshx.git Создание ssh-ключа. На Windows можно как через cmd, так и Git Bash, на *nix — просто в консоли. Но в cmd я не разбираюсь, поэтому привожу инструкцию только для Git Bash & *nix: ssh-keygen -t rsa -C "user.name@mail.domain" Можно выбрать passphrase, который повышает надёжность, но его нужно будет вводить каждый раз при использовании. Если забудете — ключ бесполезен для дальнейшего использования. После выполнения команды публичный ключ появляется соответственно в C:\Users\%username%\.ssh\id_rsa.pub ~/.ssh/id_rsa.pub Именно публичный ключ нужно передавать специалисту на той стороне. (Наверняка вы так и сделали, но всё-таки стоит об этом сказать) Если всё сделали правильно, то при попытке соединения по ssh ключ будет использоваться автоматически. Если ключ уже есть То его надо положить в c:\Users\%username%\.ssh. Если имя ключа отличается от id_rsa, то надо создать файл c:\Users\%username%\.ssh\config со следующим содержимым: Host: server.domain IdentityFile путь_и_имя_ключа

Ответ 2



На практике мне когда-то помогла эта статья - лучший пример из всего что я видел: http://habrahabr.ru/sandbox/37865/ В ней полностью показаны клиентские программы для работы с push-ом и pull-ом. У меня лично Windows недолюбливал родной Git клиент, но всегда прекрасно работает с Tortoise (есть в статье). В ней есть полное руководство по подключению. Не уверен правильная ли это аналогия, но вы можете поставить себе программу Composer и ей подобные, после чего можно через консоль Windows полностью клонировать себе репозиторий с Git-а. Если же касается более специфичного подключения именно к Git, то эта страница будет полезной: http://webhamster.ru/site/page/index/articles/comp/171 Добавил, как попросили, кратко содержимое статьи: Идем на официальную страницу Git http://git-scm.com, кликаем на Download for Windows. В открывшемся окне кликаем на Full installer for official Git. Запускаем полученный exe-шник. Я рекомендую выбрать "Run Git from the Windows Command Prompt". Все остальные опции можно оставлять по-умолчанию. После установки Git нужно перегрузиться или завершить сеанс пользователя и снова войти, чтобы применились изменения в системной переменной PATH. Далее нужно проверить, доступен ли Git для работы. В любом каталоге даем команду: git --version Если получаем информацию о версии, то Git установлен и работает. Если получаем информацию что программа git не найдена, разбираемся что сделали не так. Настройка SSH-ключей в Windows В операционной системе Windows генератор SSH-ключей включен в комплект поставки Git. Для генерации ключей необходимо запустить на выполнение файл C:\Program Files\Git\Git bash.vbs. Его можно запустить как обычный exe-шник. Откроется программа "Консоль git". В ней надо дать команду: ssh-keygen -t rsa -C "myemail@mail.ru" Будьте внимательны, в этой консоли подглючивает копи-паст, проще ввести команду вручную. В качестве email указываем свой почтовый ящик. На запрос "Enter file in which to save the key" просто нажимаем Enter. При запросе пароля "Enter passphrase" и "Enter same passphrase again" просто нажимаем Enter. В процессе генерации ключей в консоли будет выдаваться примерно следующая информация: Generating public/private rsa key pair. Enter file in which to save the key (/c/Documents and Settings/username/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Documents and Settings/username/.ssh/id_rsa. Your public key has been saved in /c/Documents and Settings/username/.ssh/id_rsa.pub. The key fingerprint is: 51:db:73:e9:31:9f:51:a6:7a:c5:3d:da:9c:35:8f:95 myemail@mail.ru После выполнения этой программы, в каталоге C:\Documents and Settings\username.ssh будут лежать файлы id_rsa и id_rsa.pub, они нам пригодятся в дальнейшем. Установка SSH-ключа в GitHub Нас колько я помню, эта часть ответа несколько изменилась в современном дизайне GitHub-а, но интуитивно можо найти. Сразу после регистрации необходимо прописать в системе GutHub свой публичный ключ шифрования (открытый SSH-ключ). Для добавления ключа, надо в правом верхнем углу нажать "Account Settings". В открывшемся окне нужно кликнуть на пункт меню "SSH Public Keys", и нажать "Add Another Public Key". Появится два поля - название ключа (Title) и содержимое ключа (Key). В поле Title можно написать название компьютера, на котором сгенерирован публичный ключ. Можно писать по-русски. В поле Key надо вставить содержимое файла id_rsa.pub. Помните, в каком каталоге они находятся? Переходим в этот каталог, открываем любым текстовым редактором файл id_rsa.pub (именно с расширением .pub, не перепутайте). Выделяем весь текст, копируем, и вставляем на странице GitHub в поле Key. После добавления ключа, компьютер может соединяться с GitHub через программу git, и никаких ошибок не должно возникать. Работа с репозитарием на GitHub через программу Git Начиная с этого момента, пляски вокруг web-интерфейса GitHub можно считать законченными. Далее можно работать только используя программу git. Вначале нужно сделать небольшую настройку программы git: указать локальной системе git имя пользователя и email. Это делается следующими командами, которые можно выполнить, находясь в любом каталоге: git config --global user.name "YourFullName" git config --global user.email myemail@mail.ru где вместо YourFullName нужно написать свое имя, а вместо myemail@mail.ru - свой email. Эти значения используются для логина на GitHub. Поэтому на месте YourFullName нужно указать ваш логин на GitHub-е, а на месте myemail@mail.ru нужно указать email, который вы вводили при генерации ключей шифрования. После этих настроек, можно заливать свои файлы в репозитарий. Переходим в каталог со своим проектом, и даем команды: git init git add . git commit -a -m 'first commit' git remote add origin git@github.com:username/reponame.git git push -u origin master После этих команд на сервере GitHub образуется копии файлов того каталога, в котором были выполнены данные команды. Далее можно уже делать коммиты, заливки на сервер GitHub изменений, считывания изменений с сервера. Но это уже совсем другая история.

Ответ 3



Вам выше уже предоставили ссылки на скачивание. Повторяться не буду. После установки потребуется выбрать каталог в системе (или создать там, где захотите), где будет лежать локальная копия того, что есть в удаленном репозитории. После этого в этой директории: git init Не забудьте настроить свой гит через: git config --global user.name git config --global user.email Это особенно актуально для продукта атлассина crucible (для код ревью). Примечание: опцию --global использовать, если вы единственный пользователь гита на данном компьютере. Если нет, настройте гит под конкретного пользователя в системе Замечание про настройку пользователя скорее опционально. Изучите официальную пользовательскую документацию на сайте либо, после установки клиента под windows запустите git --help для получения справки. Для клонирования репозитория в свою локальную папку используется: git clone ssh://username@servername.com/git/folder/here Вы также можете воспользоваться графической версией ГИТа, хотя лично я предпочитаю везде пользовать консоль, мне она кажется более информативной.

Почему необходимо инициализировать коллекции именно так?

#java #коллекции


Почему коллекции необходимо создавать таким образом:

List list = new Linkedlist();


Почему нежелательно сразу писать LinkedList?
    


Ответы

Ответ 1



Это важный прием написания хорошего ООП кода. Идея в том что так ваш код становится менее зависим от конкретных реализаций используемых модулей. В тот же самый интерфейс List можно записать LinkedList, ArrayList, CopyOnWriteArrayList и т.д. При этом, объявив список подобным образом, мы можем быть уверены что если вдруг появится необходимость подменить реализацию с LinkedList на ArrayList, то нам придется изменить только строчку с вызовом конструктора. Например LinkedList, в отличии от ArrayList, помимо интерфейса List имплементирует ещё Queue(очередь) в котором есть метод push. List list = new LinkedList(); LinkedList linkedList = new LinkedList(); ArrayList arrayList = new ArrayList(); list.add("ok"); linkedList.add("ok"); arrayList.add("ok"); list.push("error"); //ошибка при компиляции, у интерфейса List нет такого метода. linkedList.push("Ok"); arrayList.push("error"); //ошибка при компиляции, ArrayList не имплементирует Queue В примере выше, даже не смотря на то что в list у нас хранится экземпляр LinkedList, мы не можем вызвать специфичные для него методы. Интерфейс List вынуждает нас пользоваться только методами списка, а не очереди или чего-либо ещё. Использование интерфейса вместо реализации не столь важно когда коллекция(или другой объект) создаётся и используется внутри одного метода, но важно если она каким-либо образом передаётся в другие модули. Подробнее на эту тему читайте про SOLID.

Ответ 2



List — это интерфейс, а LinkedList - это класс, который имплементирует этот интерфейс. interface List содержит базовые методы add(), get(), remove() и так далее, если тебе достаточно этих методов можешь писать List<...> list = new LinkedList<..>(), если нужно использовать доп. методы которые есть в классе LinkedList тогда следует писать так LinkedList<...> linkedList = new LinkedList<...>();

Ответ 3



Если ты захочешь из базы подтянуть какие-то сущности, которые в твоих репозиториях будут сохранятся как разные листы, тебе придется как минимум каждый раз чекать модель, чтобы посмотреть какой же там лист. А инициализируя через интерфейс ты на несколько секунд упрощаешь свою жизнь. Это один из примеров и таких можно навести еще много. К примеру, если ты изменил в модели лист с array на linked, но в сервисах или контроллерах подтягивал сущности именно в array, тогда тебе придется в ручную все изменять, но иницилизируя от интерфейса эта потребность отпадает.

Ответ 4



Потому что это идеология джавы, объявлять переменные с типами интерфейса. Но скоро это изменится: https://habrahabr.ru/post/280188/ https://habrahabr.ru/post/280075/ val list = new Linkedlist();

Как прижать footer к низу страницы

#html #css



  


1



Ответы

Ответ 1



Если вы хотите сделать так, чтобы подвал (footer) был всегда внизу окна браузера при том, что на странице недостаточно контента, то можете использовать такой код: html, body { height: 100%; } #wrap { min-height: 100%; } main { padding-bottom: 100px; /*Высота футера*/ } footer { margin-top: -100px; /*Минус Высота футера*/ height: 100px; /*Высота футера*/ }

Содержимое заголовка

Основное содержимое

Содержимое подвала

Такая разметка предполагает, что все содержимое страницы хранится внутри блока div с id = wrap, а все содержимое футера в блоке footer. Блок header здесь необязателен (предполагается, что в нем хранится шапка страницы, например, меню). Блок main обязателен. Также вы можете заменить footer, main, #wrap на блоки div или другие элементы, но потребуется поправить стиль. Если вас устраивает main, #wrap, footerr, имейте в виду, что в браузере IE < 9 потребуется подключить скрипт html5shiv, поскольку старые IE не понимают теги html5

Ответ 2



Можно прижать с помощью флексбокс, тогда высота футера может быть разной, а верстка соответственно адаптивной: * { margin: 0;/*это свойство можно удалить, если вы используете reset, normalize или нечто подобное*/ } html, body { height: 100%; } body { display: flex; flex-direction: column; } .content { flex: 1 0 auto; padding: 1rem;/*это свойство можно удалить, добавлено для наглядности*/ background: #e6f2ff;/*это свойство можно удалить, добавлено для наглядности*/ } footer { flex: 0 0 auto; padding: 1rem;/*это свойство можно удалить, добавлено для наглядности*/ background: #e6ffe6;/*это свойство можно удалить, добавлено для наглядности*/ }
content
footer


Реализация highlight

#javascript #html #jquery


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


При замене html перестают работать события на , при этом элементы
могут быть разные. Можно ли делать реинициализацию(?) после замены.
Как избежать замены в тэгах? Начните для примера вводить class.


Приветствуется лаконичное и легкое решение на jQuery/JavaScript. 



$(".hint").on("click", function() {
  alert('ok');
});

$("input").on("input", function() {

  var text = $(this).val();
  $('#text').html($('#text').html().replace(RegExp("(|<\/highlight>)",
"gi"), ''));

  if (!text) return;

  var re = $('#text').html().replace(RegExp("(" + text + ")", "gi"), '$1');
  $('#text').html(re);

});
highlight {
  background: yellow;
}

a {
  text-decoration: underline;
  cursor: pointer;
}




Ответы

Ответ 1



На ответ не тянет, но так, информация к размышлению, возможно. Возьмите исходный html. Разбейте по тэгам. Сложите текст (исключая тэги), на места тэгов воткните какой-нибудь символ разделитель. в поисковый шаблон между каждым символом вставьте необязательный этот разделитель, и замените регуляркой, обернув в . Замените разделитель обратно на тэги. Описанное выше реализовано в коде ниже. $("#text, #result").on("click", ".hint", function() { alert('ok'); }); $("input").on("input", function() { console.clear() var text = $(this).val(); var html = $("#text").html().split(/(<.*?>)/); var filtered = html.filter(function(v, idx){ return idx % 2 == 0; }).join("|"); var x = text.split('').join("(\\|?)"); var re = new RegExp("(" + x + ")"); var hl = filtered.replace(re, "$1"); var z = -1; var result = hl.replace(/\|/g, () => html[z += 2] ); $("#result").html(result); }); highlight { background: yellow; } a { text-decoration: underline; cursor: pointer; }
Съешь еще этих мягких французских булок
Оно даже в ФФ вроде подсвечивает, однако получаемый html будет не валидный, например при вводе их фр вы получите их фр поэтому требуется еще провести замену всех тэгов, которые найдены между на

Ответ 2



Поиск любого текста, в том числе пересекающего различные элементы. Чтобы сильно не усложнять код, отформатировал html так, чтобы между блочными элементами был ровно один пробел. И вообще чтобы более одного пробела подряд не встречалось, иначе будет затруднительно угадать разметку при вводе поисковой строки. function getTextNodes(el) { return [...el.childNodes].flatMap( x => x.nodeType === Node.ELEMENT_NODE ? getTextNodes(x) : x.nodeType === Node.TEXT_NODE ? [x] : [] ) } document.querySelector("input").addEventListener('input', function (e) { var text = e.target.value; var container = document.querySelector(".search-content"); for (var mark of container.querySelectorAll("mark")) { mark.outerHTML = mark.innerHTML; } if (!text) { return; } var mark = document.createElement('mark'); mark.textContent = text; var nodes = getTextNodes(container) NODE: for (var q=0; q 1) { var df = document.createDocumentFragment(), last; df.appendChild(document.createTextNode(parts[0])); for(var w=1; w= text.length) { break; } else if (text.slice(p).startsWith(cur)) { p += cur.length; } else { continue NODE; } } if (cur.startsWith(text.slice(p))) { var r = text.length - p; cur = node.nodeValue; var df = document.createDocumentFragment(); df.appendChild(document.createTextNode(cur.slice(0, -l))); var m = document.createElement('mark'); m.textContent = cur.slice(-l); df.appendChild(m); node.parentElement.replaceChild(df, node); while (++q < w) { var m = document.createElement('mark'); nodes[q].parentElement.replaceChild(m, nodes[q]); m.appendChild(nodes[q]); } var df = document.createDocumentFragment(); var m = document.createElement('mark'); m.textContent = text.slice(p); df.appendChild(m); df.appendChild(last = document.createTextNode(nodes[w].nodeValue.slice(r))); nodes[w].parentElement.replaceChild(df, nodes[w]); nodes[w] = last; --q; break; } } } } }) input { line-height: 30px; font-size: 20px; border: 1px solid #333; width: 100%; box-sizing: border-box; padding: 0 5px; position: sticky; top: 8px; }

Айзек Азимова: Конец вечности

Техник Эндрю Харлан вошел в капсулу. Капсула находилась внутри колодца, образованного редкими вертикальными прутьями. Прутья плотно облегали круглые стенки капсулы и, уходя вверх, терялись в непроницаемой дымке в шести футах над головой Харлана. Харлан повернул рукоятки управления и плавно нажал на пусковой рычаг. Капсула осталась неподвижной. Харлана это не удивило. Капсула не должна была двигаться ни вверх, ни вниз, ни вправо, ни влево, ни вперед, ни назад. Только промежутки между прутьями словно растаяли, затянувшись серой пеленой, которая была твердой, но все-таки нематериальной. Харлан почувствовал легкую дрожь в желудке и слабое головокружение и по этим признакам понял, что капсула со всем своим содержимым стремительно мчится в будущее сквозь Вечность. Он вошел в капсулу в 575-м Столетии. Этот Сектор Вечности стал его домом два года назад. Никогда до этого ему не приходилось забираться в будущее так далеко. Но сейчас он направляется в 2456-е Столетие. Месяц назад при одной только мысли об этом Харлану стало бы не по себе. Его родное 95-е Столетие осталось далеко в прошлом. Это был век патриархальных традиций, в котором атомная энергия находилась под запретом, а всем строительным материалам предпочитали дерево. Век славился своими напитками, которые в обмен на семена клевера вывозились почти во все другие Столетия. Хотя Эндрю Харлан не был дома с тех пор, как он в пятнадцать лет стал Учеником и прошел специальную подготовку, его никогда не оставляла тоска по родным Временам. Между 95-м и 2456-м Столетиями пролегло почти двести сорок тысяч лет, а это ощутимый промежуток даже для закаленного Вечного. При обычных обстоятельствах все было бы именно так. Однако сейчас Харлану было не до абстрактных размышлений. Рулоны перфолент оттягивали его карманы, планы тяжким грузом лежали на сердце, мысли были скованы страхом и неуверенностью. Он машинально остановил капсулу в нужном Столетии. Странно, что Техник способен волноваться.

Тестовый список для поиска
  • Пункт 1
  • Пункт 2
  • Пункт 3
  • Пункт 4 Подсписок
    • Пункт 4.1
    • Пункт 4.2
    • Пункт 4.3


Ответ 3



Алгоритм такой: получаем список всех дочерних элементов идем по этому списку, если: это текстовый элемент textNode, то проверяем наличие highlight если это обычный элемент, то переходим к 1 пункту в контексте этого элемента class Highlight { constructor(input, content) { this.input_ = input; this.content_ = content; this.query_ = ''; this.cache_ = []; this.init_(); } // Проверяем является ли нода текстовой isTextNode_(node) { return node.nodeName === '#text'; } // Проверяет, если совпадение в тексте hasMatch_(node) { return node.textContent.includes(this.query_); } highlightNodes_(element) { const children = element.childNodes; // children не подойдет, так как не возвращает textNode for(let child of children) { if(this.isTextNode_(child) && this.hasMatch_(child)) { this.highlightByQuery_(child); } else { this.highlightNodes_(child); } } } // Будет заниматься подсветкой highlightByQuery_(node) { const queryRegexp = new RegExp(this.query_, 'ig'); // тут можно использовать html const markedNode = document.createElement('span'); markedNode.innerHTML = node.textContent .replace(queryRegexp, str => `${str}`); node.replaceWith(markedNode); // Кешируем результат, что бы потом сбросить this.cache_.push(markedNode); } resetSearch_() { for(let node of this.cache_) { const regExp = /\<\/?mark\>/g; const content = node.innerHTML.replace(regExp, ''); const textNode = document.createTextNode(content); node.replaceWith(textNode); } this.cache_ = []; this.query_ = ''; } init_() { this.input_.onchange = this.search.bind(this); } search() { this.resetSearch_(); this.query_ = this.input_.value; if(!this.query_.trim()) return; this.highlightNodes_(this.content_); } } // Собственно сам поиск const content = document.querySelector('.search-content'); const queryInput = document.querySelector('input'); const highlight = new Highlight(queryInput, content); p { line-height: 20px; padding: 0 10px; } .controls { margin: 0 0 10px 0; display: flex; justify-content: center; } input { line-height: 30px; font-size: 20px; border: 1px solid #333; padding: 0 5px; } button { background: #fff; border: 1px solid #333; margin-left: 10px; } mark { }

Айзек Азимова: Конец вечности

Полный роман можно прочитать здесь

Техник Эндрю Харлан вошел в капсулу. Капсула находилась внутри колодца, образованного редкими вертикальными прутьями. Прутья плотно облегали круглые стенки капсулы и, уходя вверх, терялись в непроницаемой дымке в шести футах над головой Харлана. Харлан повернул рукоятки управления и плавно нажал на пусковой рычаг. Капсула осталась неподвижной. Харлана это не удивило. Капсула не должна была двигаться ни вверх, ни вниз, ни вправо, ни влево, ни вперед, ни назад. Только промежутки между прутьями словно растаяли, затянувшись серой пеленой, которая была твердой, но все-таки нематериальной. Харлан почувствовал легкую дрожь в желудке и слабое головокружение и по этим признакам понял, что капсула со всем своим содержимым стремительно мчится в будущее сквозь Вечность. Он вошел в капсулу в 575-м Столетии. Этот Сектор Вечности стал его домом два года назад. Никогда до этого ему не приходилось забираться в будущее так далеко. Но сейчас он направляется в 2456-е Столетие. Месяц назад при одной только мысли об этом Харлану стало бы не по себе. Его родное 95-е Столетие осталось далеко в прошлом. Это был век патриархальных традиций, в котором атомная энергия находилась под запретом, а всем строительным материалам предпочитали дерево. Век славился своими напитками, которые в обмен на семена клевера вывозились почти во все другие Столетия. Хотя Эндрю Харлан не был дома с тех пор, как он в пятнадцать лет стал Учеником и прошел специальную подготовку, его никогда не оставляла тоска по родным Временам. Между 95-м и 2456-м Столетиями пролегло почти двести сорок тысяч лет, а это ощутимый промежуток даже для закаленного Вечного. При обычных обстоятельствах все было бы именно так. Однако сейчас Харлану было не до абстрактных размышлений. Рулоны перфолент оттягивали его карманы, планы тяжким грузом лежали на сердце, мысли были скованы страхом и неуверенностью. Он машинально остановил капсулу в нужном Столетии. Странно, что Техник способен волноваться.

    Тестовый список для поиска
  • Пункт 1
  • Пункт 2
  • Пункт 3
  • Пункт 4
      Подсписок
    • Пункт 4.1
    • Пункт 4.2
    • Пункт 4.3
Плюсы: не нужно беспокоиться про всякие обработчики, потому что работа идет с textNode, там ничего не повесить Минусы: если ввести Запрос c таким html: Запрос, то не подсветит

Ответ 4



Обработка текста содержащего html элементы в общем случае весьма не тривиальная задача. Так как то, что видит пользователь и то, как это отображено в разметке может разительно отличаться из-за стилей, и специальной работой с пробельными символами в браузере. В данном случае можно использовать следующий алгоритм: взять текстовое содержимое нужного элемента, это примерно текст, который видит пользователь. найти в нем индексы подстрок, совпадающих с введенной строкой. html-элементы можно представить в виде дерева, в котором в листовыми узлами являются текстовые элементы исходя из пункта 3, обход дерева в глубину, позволит пройтись по всему тексту от начала до конца, попутно позволяя считать индексы каждого символа в результирующей строке при обходе, можно собрать текстовые узлы, текст которых полностью либо частично входит в искомые индексы теперь осталось пройтись по выбранным узлам и в соответствии с нужными индексами заменить в них куски строк, обернув их в нужный элемент, который можно подсветить. Чтобы данный алгоритм можно было применять несколько раз - перед его применением нужно удалить элементы добавленные на прошлом ходу, чтобы устранить их дублирование. Небольшой пример: $('.hint').click(function() { console.log(this.textContent) }); function* deep(container) { // обход дерева в глубину for (var nodes = Array.from(container.childNodes); nodes.length;) { var node = nodes.shift(); // если попался элемент - добавляем дочение узлы в начало проверки if (node.nodeType == Node.ELEMENT_NODE) { nodes.unshift(...node.childNodes); continue; } // если попался текстовый узел - возвращаем if (node.nodeType == Node.TEXT_NODE) yield node; } } // ищем в контейнере текстовые узлы, в которых полностью или частично расположены искомые строки function find(container, entries) { var finded = []; var nodes = deep(container); var node = nodes.next().value; var curNodeStartIndex = 0; for (var entry of entries) { // для каждого интервала [startIndex, endIndex) соответствующего искомой строке while (curNodeStartIndex + node.textContent.length <= entry.startIndex) { // пропускаем узлы, пока не найдем узел, на который приходится startIndex curNodeStartIndex += node.textContent.length; node = nodes.next().value; } //сохраняем индекс символа в выбранном узле var start = entry.startIndex - curNodeStartIndex; while (curNodeStartIndex + node.textContent.length < entry.endIndex) { // добавляем в список новые узлы, пока не найдем узел, на который приходится endIndex curNodeStartIndex += node.textContent.length; finded.push({ node, start: start - node.textContent.length, end: node.textContent.length }); start = 0; node = nodes.next().value; } //сохраняем индекс символа в выбранном узле var end = entry.endIndex - curNodeStartIndex; finded.push({ node, start: start - node.textContent.length, end: (end - node.textContent.length) || node.textContent.length }); } return finded; } function highlight(container, textToFind, ignorecase) { var body = ignorecase ? container.textContent.toLowerCase() : container.textContent; textToFind = ignorecase ? textToFind.toLowerCase() : textToFind; // если передали пустую строку, либо общая длина текста меньше искомого фрагмента, то можно ничего не делать if (textToFind.length == 0 || body.length < textToFind.length) return; // ищем интервалы вхождений var points = [] for ( var findIndex = body.indexOf(textToFind, findIndex + 1); findIndex != -1; findIndex = body.indexOf(textToFind, findIndex + textToFind.length + 1)) { points.push({ startIndex: findIndex, endIndex: findIndex + textToFind.length }); } var nodes = find(container, points); // для каждого найденного узла вставляем в найденном месте элемент дял подсветки nodes.forEach(node => { var before = node.node.textContent.slice(0, node.start); var hl = document.createElement('mark'); hl.textContent = node.node.textContent.slice(node.start, node.end); var after = node.node.textContent.slice(node.end); node.node.textContent = after; node.node.parentNode.insertBefore(hl, node.node); hl.insertAdjacentText('beforebegin', before); }); } function removeHighlight(container) { // бежим по всем элементам подсветки и заменяем их текстовым содержимым for (hl of container.querySelectorAll('mark')) { hl.replaceWith(hl.textContent); } // сливаем все идущие подряд текстовые узлы в один. container.normalize(); } (function($) { $.fn.highlight = function(options) { var defaultOptions = { text: '', ignorecase: true } options = $.extend(defaultOptions, options); return this.each(function() { removeHighlight(this); highlight(this, options.text, options.ignorecase); }); }; })(jQuery); $('input').on('input', function() { $('#text').highlight({ text: this.value }); }).triggerHandler('input'); $('textarea').on('input', function() { console.dir(this.value); $('#text2').highlight({ text: this.value }); }).triggerHandler('input'); .text { margin: 0 0 20px 0; } hl { background-color: yellow; } textarea { position: sticky; top: 8px; width: 100%; }
Съешь еще этих мягких французских булок

Айзек Азимова: Конец вечности

Полный роман можно прочитать здесь

Техник Эндрю Харлан вошел в капсулу. Капсула находилась внутри колодца, образованного редкими вертикальными прутьями. Прутья плотно облегали круглые стенки капсулы и, уходя вверх, терялись в непроницаемой дымке в шести футах над головой Харлана. Харлан повернул рукоятки управления и плавно нажал на пусковой рычаг. Капсула осталась неподвижной. Харлана это не удивило. Капсула не должна была двигаться ни вверх, ни вниз, ни вправо, ни влево, ни вперед, ни назад. Только промежутки между прутьями словно растаяли, затянувшись серой пеленой, которая была твердой, но все-таки нематериальной. Харлан почувствовал легкую дрожь в желудке и слабое головокружение и по этим признакам понял, что капсула со всем своим содержимым стремительно мчится в будущее сквозь Вечность. Он вошел в капсулу в 575-м Столетии. Этот Сектор Вечности стал его домом два года назад. Никогда до этого ему не приходилось забираться в будущее так далеко. Но сейчас он направляется в 2456-е Столетие. Месяц назад при одной только мысли об этом Харлану стало бы не по себе. Его родное 95-е Столетие осталось далеко в прошлом. Это был век патриархальных традиций, в котором атомная энергия находилась под запретом, а всем строительным материалам предпочитали дерево. Век славился своими напитками, которые в обмен на семена клевера вывозились почти во все другие Столетия. Хотя Эндрю Харлан не был дома с тех пор, как он в пятнадцать лет стал Учеником и прошел специальную подготовку, его никогда не оставляла тоска по родным Временам. Между 95-м и 2456-м Столетиями пролегло почти двести сорок тысяч лет, а это ощутимый промежуток даже для закаленного Вечного. При обычных обстоятельствах все было бы именно так. Однако сейчас Харлану было не до абстрактных размышлений. Рулоны перфолент оттягивали его карманы, планы тяжким грузом лежали на сердце, мысли были скованы страхом и неуверенностью. Он машинально остановил капсулу в нужном Столетии. Странно, что Техник способен волноваться.

    Тестовый список для поиска
  • Пункт 1
  • Пункт 2
  • Пункт 3
  • Пункт 4
      Подсписок
    • Пункт 4.1
    • Пункт 4.2
    • Пункт 4.3


Ответ 5



Все же в мои сниппеты попал собственный код переписанный на JS. Проблему с тегами мне пожалуй проще решать на стороне сервера оборачивая чистый текст определенными тэгами, например span, и делая вызов навроде highlight('#text>span') function highlight(s,e){ var e=document.querySelectorAll(e); for ( var i=0; i|<\/highlight>)", "gi"), ''); // remove highlight if(s) e[i].innerHTML=e[i].innerHTML.replace(RegExp("("+s+ ")", "gi"), '$1'); // highlight } } с универсальными вариантами вызовов highlight