Страницы

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

понедельник, 22 октября 2018 г.

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

Помогите разрулить потоки. Я не буду предоставлять код, мне нужна просто идея.
Есть некоторое событие, по которому запускается некоторый поток. Мне нужно сделать так, чтобы каждый запуск этого потока завершал выполнение предыдущего экземпляра.
Framework 4.0 (без async / await)


Ответ

"Старый" и самый топорный способ заключается в создании потока и его убийстве при необходимости. Однако потенциально это весьма опасный способ, т.к., например, поток может оставить общие данные в неконсистентном состоянии или вовсе отказаться завершаться
class Program { private static Thread _thread;
static void Main(string[] args) { Console.ReadLine(); TriggerEventOld();
Console.ReadLine(); TriggerEventOld();
// дождемся завершения _thread.Join(); }
private static void TriggerEventOld() { if (_thread != null) { _thread.Abort(); // корректнее будет дождаться завершения _thread.Join(); }
_thread = new Thread(Foo); _thread.Start(); }
private static void Foo() { Console.WriteLine("Foo started");
try { for (int i = 0; i < 10; i++) { Thread.Sleep(500); } } catch (ThreadAbortException) { Console.WriteLine("Foo aborted"); }
Console.WriteLine("Foo ended"); } }

Лучше не связываться с Abort(), и использовать "мягкое" завершения потока с помощью ManualResetEventSlim, который послужит флагом завершения. У такого способа есть один минус -- если вы запускаете синхронный код, который может долго отвечать (например, чтение файла или запрос в сеть), то придется долго ждать завершения потока при новом запуске.
class Program { private static Thread _thread; private static ManualResetEventSlim _reset = new ManualResetEventSlim();
static void Main(string[] args) { Console.ReadLine(); TriggerEventOld();
Console.ReadLine(); TriggerEventOld();
// дождемся завершения _thread.Join(); }
private static void TriggerEventOld() { if (_thread != null) { _reset.Set(); // корректнее будет дождаться завершения _thread.Join(); }
_thread = new Thread(Foo); _reset.Reset(); _thread.Start(); }
private static void Foo() { Console.WriteLine("Foo started");
for (int i = 0; i < 10; i++) { if (_reset.IsSet) { Console.WriteLine("Foo canceled"); break; }
Thread.Sleep(500); }
if (!_reset.IsSet) { Console.WriteLine("Foo ended"); } } }

Но поскольку вы используете .NET 4.0, значит вам доступен TPL. В таком случае будет лучше воспользоваться Task и CancellationToken, с ними вы можете сделать "мягкую" остановку задачи. Преимущество новой модели заключается в том, что практически все асинхронные методы поддерживают остановку с помощью CancellationToken, поэтому код будет реагировать на завершение быстрее.
class Program { private static Task _task; private static CancellationTokenSource _cts;
static void Main(string[] args) { Console.ReadLine(); TriggerEventNew();
Console.ReadLine(); TriggerEventNew();
// дождемся завершения; // этот вызов может выбросить исключение, // если внутри возникнет необработанное исключение _task.Wait(); }
private static void TriggerEventNew() { if (_task != null) { _cts.Cancel(); // корректнее будет дождаться завершения; // этот вызов может выбросить исключение, // если внутри возникнет необработанное исключение _task.Wait(); }
// пересоздаем каждый раз, поскольку это одноразовый объект _cts = new CancellationTokenSource(); _task = Task.Factory.StartNew(() => FooNew(_cts.Token), _cts.Token); }
private static void FooNew(CancellationToken token) { Console.WriteLine("FooNew started");
for (int i = 0; i < 10; i++) { if (token.IsCancellationRequested) { Console.WriteLine("FooNew aborted"); break; }
Thread.Sleep(500); }
if (!token.IsCancellationRequested) { Console.WriteLine("FooNew ended"); } } }
Если будете использовать token.ThrowIfCancellationRequested(), не забудьте обернуть код в блок try/catch c проверкой токена:
try { ... token.ThrowIfCancellationRequested(); ... } catch (OperationCanceledException e) { if (e.CancellationToken != token) { // отмена была вызвана не нами, бросаем исключение throw; } }

mysql обрезает большое текстовое поле в запросе

SELECT q.*, a.answer FROM `questions` q LEFT JOIN ( SELECT question_id, GROUP_CONCAT(text SEPARATOR '|| ') answer FROM answers GROUP BY question_id ) a ON q.uid = a.question_id WHERE q.deleted = 0 GROUP BY q.uid
Этот запрос выбирает вопросы и ответы к ним, склеивая их. В табличке ответы хранятся в виде text. При выборке и конкатенации часть текста обрезается. Например если у меня 3 больших ответа, мне возвращает где-то целый первый ответ и половину второго. Если в базе все эти ответы сделать маленькими - все отлично. В чем здесь проблема?


Ответ

У функции GROUP_CONCAT есть ограничение на объем выводимых данных. По умолчанию 1024 символа для каждого объединения - для каждой выводимой строки. Если размер данных, полученных в результате конкатенации, больше, выводимый текст будет обрезан.
Чтобы расширить размер, нужно выполнить команду:
SET SESSION group_concat_max_len = 1000000;
или SET @@group_concat_max_len = 1000000; (аналогична предыдущей).
Но данная команда будет применена только к текущей сессии. По завершении сессии, например, при открытии нового соединения, значение данной переменной вернётся к начальному значению. Для установки глобальной переменной нужно выполнить следующую команду:
SET GLOBAL group_concat_max_len = 1000000;

Как посмотреть список всех id которые используются на странице в коде html?

Как посмотреть список всех id которые используются на странице в коде html?


Ответ

Можно получить все элементы, у которых есть id, и вывести список:
var ids = document.querySelectorAll('[id]');
Array.prototype.forEach.call( ids, function( el, i ) { console.log( el.id ); // log the ID });
Если нужен массив из id
var ids = document.querySelectorAll('[id]');
var arr = Array.prototype.map.call( ids, function( el, i ) { return el.id; });
P.S. взял с английской версии, автор ответа @user113716

GC (GarbageCollector) - возможно ли изменить параметры вызова?

Я понимаю что GC (GarbageCollector) вызывается сам. Я знаю что его можно вызывать вручную, но не желательно...
А возможно ли как-то изменить настройки которые напрямую влияют на частоту вызова GC?
Вот есть у меня некая апликуха, которая обрабатывает множество файлов... Сначала открывает, потом изменяет и присваивает в другую переменную, потом закрывает... и так по кругу.
Сама апликуха постоянно кушает оперативку от 1 гига до 8 гиг пока не вызовется GC.
Мне интересно, возможно ли без вручного вызова, добится результата что бы апликуха кушала не больше, скажем, 3х гигабайт.


Ответ

Можно в классе GCSettings поиграться со свойством LatencyMode. На время обработки множества файлов задать значение Batch. После обработки вернуть в Interactive
Если версия фреймворка позволяет, можно компактировать LOH: периодически задавать свойству LargeObjectHeapCompactionMode значение CompactOnce
Используется ли в приложении неуправляемая память? Если да, то следует вызывать метод GC.AddMemoryPressure (и не забывать в пару к нему RemoveMemoryPressure).
Ещё можно попробовать в конфиге включить серверный сборщик мусора.

Как рекурсию переделать в итеративный метод.(Diamond-Square)

Вот тут человек говорит:
переделал все в итеративный метод, чтобы корректно считалось по слоям
У меня такая-же ситуация есть методы, только не знаю как их вызывать послойно? Я не могу зарегистрироваться на этом форуме, что бы спросить его. Там же на форуме он кратко объясняет принцип работы алгоритма.
Попытаюсь объяснить. Метод Square на вход получает два угла, левый нижний и правый верхний и считает центральную точку заданного таким образом квадрата. Diamond принимает на вход только координаты точки, которую надо посчитать (т.е. середины квадрата из предыдущего шага) и половинную сторону этого квадрата, считает координаты четырех точек справа, слева, сверху и снизу от принятой точки и также, как и в Square, усредняет их и прибавляет случайное число, пропорциональное стороне. Если любая из координат этих четырех точек выходит за границы карты, то он берет значение точки, лежащей с другой стороны, т.е. как бы сворачивает плоскость. Метод DiamondSquare комбинирует эти два метода, принимая те же параметры, что и Square. Сначала он вызывает Square для входного квадрата, потом Diamond для всех четырех середин своих сторон, а потом рекурсивно вызывает сам себя для четырех под-квадратов до тех пор, пока не посчитает все пиксели.
Сама рекурсивная функция:
public void diamondSquare(Vec2int L, Vec2int R, int l) { if (l > 0) { Vec2int[] points = GetPoints(L, R, l); foreach (Vec2int elem in points) { diamond (elem, l); } square (L, new Vec2int (points [3].x, points [2].y), l); square (new Vec2int (points [3].x, points [2].y), R, l); square (points [0], points [1], l); square (points [3], points [2], l);
diamondSquare (L, new Vec2int (points [3].x, points [2].y), l / 2); diamondSquare (new Vec2int (points [3].x, points [2].y), R, l / 2); diamondSquare (points [0], points [1], l / 2); diamondSquare (points [3], points [2], l / 2); } }
Остальной код:
public int size = 32; [Range(0,1f)] public float Roughnees = 0.5f; private float[,] map;
public void square(Vec2int L, Vec2int R, int l) { Vec2int Center = new Vec2int (R.x - l, R.y - l); float a = map [L.x, L.y]; float b = map [L.x, R.y]; float c = map [R.x, R.y]; float d = map [R.x, L.y]; map [Center.x, Center.y] = (a + b + c + d) / 4 + Random.Range (-l / (size - 1) * (Roughnees), l / (size - 1) * (Roughnees)); }
public void diamond(Vec2int point,int l) { float a, b, c, d;
if (point.y - l >= 0) a = map [point.x, point.y - l]; else a = map[point.x, size - l];
if (point.x - l >= 0) b = map [point.x - l, point.y]; else b = map [size - l, point.y];
if (point.y + l < size) c = map [point.x, point.y + l]; else c = map [point.x, l];
if (point.x + l < size) d = map [point.x + l, point.y]; else d = map [l, point.y];
map [point.x, point.y] = (a + b + c + d) / 4 + Random.Range (-l / (size - 1) * Roughnees, l / (size - 1) * Roughnees); }

public static Vec2int[] GetPoints(Vec2int L, Vec2int R, int l) { return new Vec2int[] { new Vec2int (L.x, L.y + l), new Vec2int (R.x - l, R.y), new Vec2int (R.x, R.y - l), new Vec2int (L.x + l, L.y) }; } public struct Vec2int { public int x; public int y; public Vec2int(int x,int y){ this.x=x; this.y=y; } }
Так-же я был бы рад ссылкам на то что можно почитать в этом направлении.
Важно заметить, что эти две высоты, которые достались нам на предыдущем шаге, должны быть уже посчитаны — поэтому обсчет нужно вести «слоями», сначала для всех квадратов выполнить шаг «square» — затем для всех ромбов выполнить шаг «diamond» — и перейти к меньшим квадратам.
Из статьи на хабре.
В моём случае рекурсия уходит в глубь для левого нижнего квадрата и каждая его правая и верхняя стороны неверно считается, и только после того как эта рекурсия заканчивается, начитается следующая для правого верхнего, для которого тоже неверно считаются левая и нижняя стороны.
Количество вызовов методов на первых 3 итерациях при разрешение картинки 64px 1 x Square и Diamond 4 x Square и Diamond 16 x Square и Diamond И для каждого метода нужно знать координаты.


Ответ

Пару дней я только размышлял как решить мою проблему, начал смотреть в сторону yield, изучал его(правда так практически ни чего о нем и не понял), сегодня принялся экспериментировать с ним, и в это время пришла небольшая идея, которую я реализовал отказавшись от yield в процессе. В общем проблема решена, картинка генерируется правильно и достаточно быстро, с настройкой разрешения и шумности. Вот такие картинки генерирует:
Сам код:
using System.Collections; using System.Collections.Generic; using Global; using UnityEngine;
public class DiaSqu : MonoBehaviour { public int size; public float Roughnees = 0.5f;
Material mat; float[,] map; Texture2D GeneratedTexture;
void Awake() { size++;
mat = gameObject.GetComponent().material; GeneratedTexture = new Texture2D(size, size);
map = new float[size, size]; map[0, 0] = Random.Range(0.3f, 0.6f); map[0, size - 1] = Random.Range(0.3f, 0.6f); map[size - 1, size - 1] = Random.Range(0.3f, 0.6f); map[size - 1, 0] = Random.Range(0.3f, 0.6f);
} void Start() { Vec2int Left = new Vec2int(0, 0); Vec2int Right = new Vec2int(size - 1, size - 1);
List box = new List(); box.Add(new Box[] { new Box(Left, Right) });
for (int l = size; l > 0; l /= 2) //Генерация box = Generate(box);
for (int i = 0; i < size; i++) //Запись в текстуру for (int j = 0; j < size; j++) GeneratedTexture.SetPixel(i, j, new Color(map[i, j], map[i, j], map[i, j], 0));
GeneratedTexture.filterMode = FilterMode.Trilinear; GeneratedTexture.Apply(); mat.mainTexture = GeneratedTexture; } public List Generate(List input) { List next = new List(); foreach (Box[] Arr in input) foreach (Box item in Arr) next.Add(Square(item)); foreach (Box[] Arr in input) foreach (Box item in Arr) diamond(item); return next; } public Box[] Square(Box box) { Vec2int Center = new Vec2int(box.R.x - box.HalfLength, box.R.y - box.HalfLength); map[Center.x, Center.y] = (map[box.L.x, box.L.y] + map[box.L.x, box.R.y] + map[box.R.x, box.R.y] + map[box.R.x, box.L.y]) / 4 + Random.Range(-box.Length * Roughnees / (size - 1), box.Length * Roughnees / (size - 1)); return new Box[]{ new Box(box.L,Center), new Box(Center,box.R), new Box(new Vec2int (box.L.x, box.L.y + box.HalfLength),new Vec2int (box.R.x - box.HalfLength, box.R.y)), new Box(new Vec2int (box.L.x+box.HalfLength, box.L.y),new Vec2int (box.R.x , box.L.y+box.HalfLength)) }; } public void diamond(Box box) { float a, b, c, d; Vec2int Center = new Vec2int(box.L.x + box.HalfLength, box.R.y - box.HalfLength); Vec2int[] points = new Vec2int[] { new Vec2int (Center.x-box.HalfLength,Center.y), //Left new Vec2int (Center.x,Center.y+box.HalfLength), //Top new Vec2int (Center.x+box.HalfLength,Center.y), //Right new Vec2int (Center.x,Center.y-box.HalfLength) //Bottom }; foreach (Vec2int point in points) { if (point.y - box.HalfLength >= 0) a = map[point.x, point.y - box.HalfLength]; else a = map[point.x, size - 1 - box.HalfLength]; if (point.x - box.HalfLength >= 0) b = map[point.x - box.HalfLength, point.y]; else b = map[size-1 - box.HalfLength, point.y]; if (point.y + box.HalfLength < size - 1) c = map[point.x, point.y + box.HalfLength]; else c = map[point.x, box.HalfLength]; if (point.x + box.HalfLength < size - 1) d = map[point.x + box.HalfLength, point.y]; else d = map[box.HalfLength, point.y]; map[point.x, point.y] = (a + b + c + d) / 4 + Random.Range(-box.Length * Roughnees / (size - 1), box.Length * Roughnees / (size - 1)); } } public struct Box { public Vec2int L; public Vec2int R; public int HalfLength; public int Length;
public Box(Vec2int L, Vec2int R) { this.L = L; this.R = R; Length = R.x - L.x; HalfLength = Length / 2; } } }
Структура из Global public struct Vec2int {    public int x;    public int y;    public Vec2int(int x, int y)    {       this.x = x;       this.y = y;    } }

Реализация Event

При помощи ILSpy, гугла и десятка-другого нецензурных слов, мне удалось точно воспроизвести реализацию методов Add и Remove стандартного event
В итоге код события выглядит так, во всяком случае после компиляции в Release, IL-код получается эквивалентным на 100%. В Debug - он естественно отличается, но незначительно, а именно в части проверки условия цикла.
//field-like объявление события public event Action SampleEvent1;
//итоги декомпиляции private Action eventDelegate; public event Action SampleEvent2 { add { Action current = eventDelegate, Action comparer; do { comparer = current; Action combine = comparer + value; current = Interlocked.CompareExchange(ref eventDelegate, combine, comparer); } while (!object.ReferenceEquals(current, comparer)); } remove { Action current = eventDelegate, Action comparer; do { comparer = current; Action combine = comparer - value; current = Interlocked.CompareExchange(ref eventDelegate, combine, comparer); } while (!object.ReferenceEquals(current, comparer)); } }
А теперь вопрос знатокам: я понимаю что это все нужно для поддержки многопоточности и что использование lock может приводить к взаимным блокировкам, но я не до конца понимаю как и, самое главное, почему работает этот вариант.


Ответ

Смотрите.
Подписка на/отписка от событий должны быть атомарными, чтобы не было возможно, что кто-то подписался, а событие не приходит. Старые версии делали блокировку:
private EventHandler _myEvent; public event EventHandler MyEvent { add { lock (this) _myEvent += value; } remove { lock (this) _myEvent -= value; } }
Недостаток этого метода — блокировка требует объекта, а какой объект брать? Можно взять «невидимый» объект, но этот объект должен быть тогда как-то специфицирован в стандарте и доступен для использования (например, если мы хотим под той же блокировкой прочитать значение делегата), что не так уж и хорошо, поскольку предписывает деталь имплементации. Поэтому используется this
Но this в свою очередь ведёт к другой проблеме: он может быть заблокирован снаружи, кем угодно! Поэтому было решено отказаться от этой идеи, и перейти к неблокирующему (lock-free) алгоритму, который не требует блокировочного объекта, и вдобавок ко всему просто быстрее и эффективнее.

Как это работает? А вот как. Переименую немного переменные:
Action eventDelegate;
public void AddSampleEvent1(Action value) { Action current = eventDelegate; Action noncombined; do { noncombined = current; Action combined = (Action)Delegate.Combine(noncombined, value); current = Interlocked.CompareExchange(ref eventDelegate, combined, noncombined); } while (current != noncombined); }
Если посмотреть, что делает Interlocked.CompareExchange, это можно переписать для ясности так:
Action eventDelegate;
public void AddSampleEvent1(Action value) { Action current = eventDelegate; Action noncombined; do { noncombined = current; Action combined = (Action)Delegate.Combine(noncombined, value); atomic // фиктивное ключевое слово { if (noncombined == eventDelegate) eventDelegate = combined; current = eventDelegate; } } while (current != noncombined); }
Что происходит? В current на начало итерации цикла будет значение eventDelegate. Мы запоминаем его во временную переменную noncombined, и добавляем value, получая делегат combined. Теперь мы пытаемся записать результат назад. Если в этой точке наш делегат никто не успел поменять из другого потока (а так скорее всего и будет), то Interlocked.CompareExchange завершится успешно, запишет делегат на место, и в current будет старое значение делегата. Это завершит цикл, проверка current != noncombined даст false
Если же пока мы пытались комбинировать, другой поток изменил eventDelegate, то проверка условия в Interlocked.CompareExchange завершится неуспешно. В этом случае в eventDelegate нельзя ничего писать, ведь мы потеряем изменённое значение! Тогда мы просто записываем это новое значение в current и уходим на следующую итерацию (проверка current != noncombined даст true). На следующей итерации мы сделаем то же самое: с текущим значением eventDelegate попробуем скомбинировать новый делегат, и записать на место, проверяя при этом, никто ли не поменял тем временем eventDelegate снова. Это по идее типичная неблокирующая техника, я видел много подобного кода в неблокирующих алгоритмах.

Как получить комментарии пользователя, оставленные в конкретном сообществе в vk

Как получить все комментарии конкретного пользователя, оставленные на стене под постами в конкретном сообществе в vk?
Я рассмотрел все методы, существующие в vk api и пока не нашел способа выполнить данную задачу.
В качестве исходных данных в этой задаче даны id пользователя и id сообщества.
Вот пример того, как я это пытался реализовать:
for i in range(200): url = "https://api.vk.com/method/wall.get?owner_id=%s&offset=%s&count=1" % (self.text1.toPlainText(), i) response = requests.get(url).text parsed_string = json.loads(response)
url1="https://api.vk.com/method/wall.getComments?owner_id=%s&post_id=%s&count=100" %(self.text1.toPlainText(), parsed_string['response'][1]['items']['id'])
response1 = requests.get(url1).text parsed_string1 = json.loads(response1)
for j in range(1, len(parsed_string1['response'])): if parsed_string1['response'][j]['items']['from_id']==self.text2.toPlainText(): item1 = QTableWidgetItem(parsed_string1['response'][j]['items']['text']) item2 = QTableWidgetItem(str(datetime.datetime.fromtimestamp(parsed_string1['response'][j]['items']['date']))) self.tablewidget.setItem(i-1, 0, item1) self.tablewidget.setItem(i-1, 1, item2)
Но в таком случае происходят слишком частые запросы к серверу, да и этот вариант слишком муторный. Подскажите, пожалуйста, в каком направлении мне двигаться и какие у вас есть мысли по этой теме.


Ответ

VK API позволяет получить комментарии только для определенного объекта за один запрос. Например, можно получить список комментариев к конкретному посту на стене с помощью метода wall.getComments. Из этого списка нужно будет отобрать комментарии нужного пользователя.
Чтобы получить комментарии сразу к нескольким постам можно воспользоваться хранимыми процедурами, либо методом execute. Метод execute в качестве параметра принимает код хранимой процедуры и выполняет его. ВКонтакте поддерживает хранимые процедуры с возможностью до 25 обращений к бд внутри одной процедуры. Таким образом мы можем получить за раз комментарии сразу к нескольким постам.
Как написать процедуру

Для этого можно воспользовать функционалом, который предоставляет ВК. Первым делом Вам понадобится приложение для доступа к API. Создать его можно тут (кликабельно) - кнопка Создать приложение. После создания зайдите в редактирование приложения, перейдите в раздел Хранимые процедуры и нажмите Добавить новую процедуру

Теперь нужно написать саму процедуру. Следующая процедура будет возвращать комментарии конкретного пользователя к 10 постам:
var owner_id = Args.owner_id; var user_id = Args.user_id; var offset = Args.offset; var post_count = Args.post_count;
if (post_count == null) post_count = 10;
// Получаем список постов var posts = API.wall.get({ "owner_id": owner_id, "offset": offset, "count" : 100, });
var i = 0; var userComments = {};
while(i < posts.items.length && i < post_count) { var post_id = posts.items[i].id; var comments = API.wall.getComments({ "owner_id": owner_id, "post_id": post_id,
"count" : 100, });
var j = 0; while(j < comments.items.length) { if (user_id == null || comments.items[j].from_id == user_id) userComments.push(comments.items[j]);
j = j + 1; }
i = i + 1; }
return userComments;
Как вызвать хранимую процедуру

Вызвать можем 2мя способами:
Через созданное ранее приложение. Это возможно только с помощью токена данного приложения. Через метод execute. Подойдет токен любого VK приложения.
Соответственно для получения списка комментраиев Вам нужно обратиться:
В первом случае к https://api.vk.com/method/execute.getCommentsFromPosts, передав соответствующие параметры. Во втором к https://api.vk.com/method/execute, передав в качетве параметра code содержимое хранимой процедуры.

Почему нельзя вложить блок в блочный элемент

Почему нельзя внести div внутрь p? Если внести h1 или же a, то всё работает.
p { width: 300px; height: 150px; border: 1px black solid; display: block; } p div { width: 50%; height: 100%; background: red; }



Ответ

в спецификации указано следующее:
A p element's end tag may be omitted if the p element is immediately followed by an address, article, aside, blockquote, div, dl, fieldset, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, main, nav, ol, p, pre, section, table, or ul, element, or if there is no more content in the parent element and the parent element is not an a element.

закрывающий тег элемента p может быть опущен если p элемент расположен сразу за address, article, aside, blockquote, div, dl, fieldset, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, main, nav, ol, p, pre, section, table, or ul элементами, или если больше нет содержимого в родительском элементе или родительский элемент не a/
console.log(document.querySelectorAll('p').length); p { width: 300px; height: 150px; border: 1px black solid; display: block; } p div { width: 50%; height: 100%; background: red; }


Как упростить схему деплоя?

Первый раз работаю в небольшой команде на внутрикорпоративном проекте. Изучить гит более-менее осилил. Теперь мучаюсь с деплоем. Суть такова:
Используем стандартную схему веток (master, develop, topic). Программируем и верстаем у себя на локалке. Есть боевой сервер. Он же и git-сервер. Он же и тестовый сервер :) Сервер содержит 2 веб-приложения. Первое мы пуллим из master-ветки — релиз готов, второе — из develop — тестируем, прежде чем мастер пулить.
Так вот, чтобы банально выложить малюсенькое изменение feature ветки в продакшн (или хотя бы в тест) мне приходится превозмогать рутину:
Переключиться с feature на develop, обновить ветку. Смержить feature, запушить develop Переключиться на master, обновить её Смержить develop, запушить master Подключиться к боевому серверу сделать пулл на develop-приложении Подключиться к боевому серверу сделать пулл на master-приложении ??? "А тут ещё букву поправьте, пожалуйста" goto 1
Это можно ли как-то всё упросить? Я уверен, что-то делаю неправильно.


Ответ

Пункты 1-2 - это очень упрощенный (где убрано к примеру тестирование) процесс, который делает каждый разработчик. Это его обычный цикл.
Пункт 3-4 - это релиз. Он не должен делать обычным разработчиком. Он делается релиз-менеджером (или ответственным человеком, назначенным на этом). Он не делается на каждый чих, а по процессу - раз в две недели или два раза в день
Пункты 5-8 делаются нажатием одной (максимум двух кнопок) или запуском одного скрипта. Он запускается на специальном билд сервере (для маленькой такой компании это может быть одна машина и для сборки, и для тестов и для репозитория). Сам скрипт сборки обычно делает следующее
git clone / git archive прогон скрипта, который фиксит конфиги, шаблоны (вы же не хотите показывать всем программистам пароли к базе на проде?) запуск скрипта, который процессит css, минимизирует js и тому подобное. прогон юнит тестов (они здесь, так как после минимизации могут быть проблемы:) ) архивирование и занесение архива в надежное место подключаемся к прод серверу(серверам) и заливаем туда архив. архив распаковывается на сервере в отдельную папку, правится конфиг nginx/apache или симлинка и сервер рестартует. (можно конечно остановить сервер, перетереть файлы и запустить сервер, но если что то пошло не так...). на проде проганяются минимальные тесты (к примеру, что главная страница возвращает 200 код, а не 500). и в git добавляется тег с ссылкой на релиз.
Этот скрипт пишеться один раз и потом подганяется по мере надобности.
также этот скрипт следует дополнить, что бы он мог работать и с develop веткой.
Теперь упрощаем жизнь. В хуки на гит сервере добавляем этот скрпит, что бы при пуше в девелом/мастер автоматом запускалось и, как результат, деплоилось на тестовый сервер/прод. Мердж в мастер обычным программистам запрещается.
Теперь все выглядит так. Разработчик взял фичу, сделал под нее ветку, сделал. После мержда в девелом (или через мердж реквест) его код автоматом выливается на тестовое окружение. Если вдруг так случилось, что он все сломал - он должен фиксить.
Если так не подходит, можно скрипт запускать на CI - один с самых популярных - jenkins. В результате деплой - это просто нажать одну кнопку.
Q/A
а почему не пулить прямо на боевом сервере? Если кто то уведет сервер, у него будет доступ к полной истории разработки. Это нужно? у меня никто не уведет историю гита, поэтому я буду пулить. уже было зачем сколько сложностей с скриптом? А представьте, что багу нашли среди ночи и нужно срочно фиксить. Наличие такого скрипта сильно упрощает жизнь. а можно без тестов? можно. Но лучше сделать какие-то минимальные.

Убрать полосы прокрутки Console C#

Пишу мини-игру на Console C#. Для более красивого отображения хочется убрать полосы прокрутки снизу и сбоку консоли. В свойствах консоли такого момента не нашел. Если есть способы , то подскажите , пожалуйста


Ответ

Следует сделать размеры буфера консоли и окна консоли одинаковыми.
Вероятно, следует использовать Console.SetBufferSize и Console.SetWindowSize

Как ограничить область видимости переменных в jQuery?

У меня есть несколько кусков кода, которые используют переменные с одинаковыми именами:
var owl = $('.banner__carousel');
...
var owl = $('.contact__carousel');
Раньше, чтобы не было конфликтов, я просто оборачивал каждый такой кусок в
$(function() { ... });
Пока не узнал, что это сокращение для
$(document).on('ready', function() { ... });
Если ли какой-либо другой способ ограничить видимость переменной (кроме как оборачивать ее в другую функцию и давать ей еще одно название).


Ответ

В стандарте ECMAScript 5 такой возможности нет. Переменные, объявленные через var, ограничены только телом функции, в которой они объявлены.
В стандарте ECMAScript 6 стало возможным объявлять переменные через let и const. Такие переменные видны только внутри контейнера {}, причем только после своего объявления.

Как убрать рамку вокруг button, input и некоторых других элементов в Firefox? [дубликат]

На данный вопрос уже ответили: Как в Firefox убрать рамку для элементов таблицы в фокусе? 3 ответа Применяю такой способ:
* { outline: 0 !important; }
В Chrome все работает, а вот Firefox наотрез отказывается принимать этот код.


Ответ

Данная проблема может возникнуть и на input'ах. При этом, блоки могут иметь еще и лишний отступ. Поэтому надежнее будет написать так:
// Remove border and padding in Firefox ::-moz-focus-outer, ::-moz-focus-inner { border: 0; padding: 0; }

React.js. Когда использовать компонент?

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

блок 1 и блок 3, как понимаю, однозначно должны описываться как компоненты, потому что представляют собой функциональные блоки.
блоки 2 - входят в навбар и тоже описываются как компоненты.
блок 3 - отдельный компонент, содержит дудл, строку поиска и кнопки поиска. Строка поиска и кнопки это отдельные компоненты? А нужно ли выделять дудл в отдельный компонент (допустим он никогда не меняется)?
блок 4 - футер. Описывать его отдельным компонентом, если он всегда неизменен? Или его включать в компонент, который описывает целиком главную страницу?


Ответ

Контейнер (container или умный компонент) - это компонент унаследованный от Component и содержащий логику и/или изменяющий свое состояние и не имеющий собственных стилей. Используется для порождения и инициализации других компонентов. Его так же можно назвать statefull. Презентационный (presentational или глупый компонент) - это компонент унаследованный от Component не имеющий логики и не изменяющий свое состояние. Может иметь собственные стили. Так же его называют еще stateless. Применяется для отображения данных, как правило полученных через props. Сейчас его использовать нет смысла, так как для его замены был создан новый вид компонентов описываемый ниже. Функциональные (или глупые компоненты так же являющиеся презентационными) - это компоненты-функции которые не имеют логики и не хранят состояние и имеют собственные стили. Так же называются stateless. В их обязанность входит отображать данные полученные через props Чистый (pure) - компонент унаследованный от PureComponent, может относится как к первой категории так и второй и третей. В его задачу входит производить неглубокое сравнение состояния компонента чтобы избежать лишнего рендера и избавить программиста от написания лишней проверки.
Этого должно хватить для понимания где что и когда использовать, но все равно добавлю, что лучше писать как можно меньше компонентов-контейнеров.
Что касается понимания когда использовать компонента, а когда элемент, то проще объяснить на простом примере -
// так можно, но лучше не делать


// так будет более правильно const ButtonGroup = ({children}) => (
{children}
);

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

Но лично я предпочитаю и поэтому советую писать вот так -

Ведь очень часто бывает так, что из головы вылетают детали собственного приложения и очень важно суметь освежить его в памяти одним охватом. А для людей которые впервые знакомятся с кодом второй вариант вообще подарок, так как очень сложно воссоздать в голове приложение не по дереву, а по классам из файлов. Но есть исключения, когда кода будет действительно много, то придется делать как в первом варианте, но все равно стараться как можно больше уместить в одном компоненте. Просто очень часто вижу как пишут App => Header + Footer. Идешь в Header, а там только один компонент, как например ButtonGroup. Потом идешь в этот ButtonGroup а там ещё один компонент. И так пока дойдешь до последнего уже забываешь откуда пришел и зачем.
А что качается конкретно Вашего случая, то минимум мог бы выглядеть так -

Как получить Html из буфера обмена в формате Unicode?

Программа берет содержание буфера, в котором хранится HTML, и должна сделать над ним какую-то работу.
Но проблема в том, что в нем кириллица и нужно что-то делать с кодировкой…
Пробовал перекодировать, но у некоторых пользователей возникают кракозябры:
var bytes = Encoding.Default.GetBytes(source); return Encoding.UTF8.GetString(bytes);
Пробовал HTML из буфера, который иногда вызывает кракозябры, сам прогонять через программу и у меня всё нормально.
Может дело в каких-то настройках Windows?
Какие существуют более универсальные варианты перекодирования?
Все пользователи (в том числе и я) используют Google Chrome, а значит, что это не проблема браузера.


Ответ

Понятие кодировки возникает только при сохранении строки на диск (в виде отдельных байт) или при передачи по сети (в виде байт).
То, что вы считаете ситуацией "строка source в неправильной кодировке" - это ложная проблема. Т.к. проблема кодировки возникает только при преобразовании в байты - то на самом деле ваша проблема это
"строка source была прочитана из массива байт с указанием неправильной кодировки".
И править надо это не "перекодированием". После прочтения строки из байт с использованием неправильной кодировки нет 100% рабочего способа ее "исправить". Есть только костыли вроде "записать ее назад в байты с указанием неправильной кодировки (надеясь что байты получатся те же самые), а потом еще раз прочитать с указанием правильно". Т.е. вы пытаетесь построить цепочку:
Есть байты строки в кодировке A Прочитать их как строку в кодировке B Увидеть кракозяблы Записать кракозяблы обратно с указанием кодировки B (использовать операцию, обратную (2) надеясь получить оригинальные байты, те же, что были в (1) Прочитать байты (те же, что были в (1)) в строку, но уже с указанием кодировки A
Код в вашем примере делает пункты 3-5. Код для 1-2 вы не привели. При этом очевидно, что в полной цепочке пункты 2-4 избыточны, и выглядеть она как
Есть байты строки в кодировке A Прочитать байты в строку с указанием кодировки A
Вам нужно исправить то место, где вы читаете source из массива байт/из сети/из буфера обмена, указав в нем правильную кодировку. "Перекодирование стоит использовать только в случае, если вы получаете кривую строку сразу в виде string из стороннего источника.

К сожалению, Cliboard.GetText(TextDataFormat.Html) - это именно такой источник.
HTML Clipboard Format выдает содержимое в виде байт именно в UTF-8.
Реализация чтения байт в HTML-строку в Cliboard выглядит вот так
if (format.Equals(DataFormats.Text) || format.Equals(DataFormats.Rtf) || format.Equals(DataFormats.OemText)) { data = ReadStringFromHandle(hglobal, false); } else if (format.Equals(DataFormats.Html)) { if (WindowsFormsUtils.TargetsAtLeast_v4_5) { data = ReadHtmlFromHandle(hglobal); } else { // This will return UTF-8 strings as an array of ANSI characters, which makes it the wrong behavior. // Since there are enough samples online how to workaround that, we will continue to return the // incorrect value to applications targeting netfx 4.0 // DevDiv2 data = ReadStringFromHandle(hglobal, false); } }
Собственно, комментарий полностью объясняет поведение.
при компиляции под 4.5 и более поздние фреймворки вы получите сразу валидную строку при компиляции под 4.0 и более ранние версии - вы получите получите байты в UTF-8, прочитанные как Encoding.Default, через new string((sbyte*)ptr)
Соответственно, в <=4.0 ваш хак с перекодированием обязателен и полностью валиден. В >=4.5 он гаранитированно невалиден и избыточен.

Ставить линию между 3 div-ами

Помогите между блоками ставить линии так чтобы было адаптивно
Html
*{ margin: 0px; padding: 0px; } .culture { text-align: center; padding: 80px 50px; background: #F9F9F9; } .culture h1 { font-family: "Montesrrat", sans-serif; font-size: 40px; font-weight: bold; color: #222; text-transform: uppercase; } .culture p { font-family: "Roboto Slab", serif; font-size: 20px; color: #777; } .culture .value { display: inline-block; width: 33%; margin-top: 50px; } .culture .value .line { width: 50%; height: 2px; background: #787878; display: inline-block; vertical-align: middle; position: relative; } .culture .value .linel { left: -100px; } .culture .value .liner { right: -100px; } .culture .value .border { border: 3px solid #787878; border-radius: 50%; display: inline-block; margin-bottom: 15px; vertical-align: middle; } .culture .value .border img { padding: 12px; } .culture .value h1 { font-size: 18px; font-family: "Montesrrat", sans-serif; font-weight: bold; color: #222; } .culture .value p { font-size: 14px; color: #777; font-weight: "Roboto Slab", serif; }

culture and values

Proin iaculis purus consequat cure.

val1

work-life balance

Proin iaculis purus consequat sem cure digni ssim. Donec porttitora entum suscipitn aenean rhoncus posuere odio in tincidunt.

val2

quality over quantity

Proin iaculis purus consequat sem cure digni ssim. Donec porttitora entum suscipitn aenean rhoncus posuere odio in tincidunt.

val3

deliver excellence

Proin iaculis purus consequat sem cure digni ssim. Donec porttitora entum suscipitn aenean rhoncus posuere odio in tincidunt.



Ответ

holder этих 3 элементов , дать ему background по средине линию , а блокам background , выстроить правильно и отступы margin
Код по ссылке
.parent { width:200px ; height: 100px; background: linear-gradient(to left,#000,#000) no-repeat; background-size:100% 2px; background-position: 0 50%; overflow: hidden; } .item { float: left; width:30% ; height: 100px; background: #fff; margin-right: 5%; } .item:last-of-type { margin-right: 0; } .item-inner { width:50%; margin:0 auto; height: 100px; background: blue; }


C++: Как распарсить json?

Имеется примерно такая json строка:
{"response":[{"id":210700286,"first_name":"Lindsey","last_name":"Stirling"}]}
Как из неё получить значения firstname и lastname?
string firstname = "Lindsey"; string lastname = "Stirling";


Ответ

Воспользуйтесь какой-нибудь библиотекой, например nlohmann/json
Обратите внимание, что в коде ниже используется удобная запись строковых литералов без экранирования в форме R"(строка, которая может содержать кавычки. круглые скобки являются частью синтаксиса и не относятся к строке)"
#include "json.hpp" using json = nlohmann::json;
int main() { string responseString = R"({"response":[{"id":210700286,"first_name":"Lindsey","last_name":"Stirling"}]})"; json responseJson = json::parse(responseString); json object = responseJson["response"]; string first_name = object[0]["first_name"]; string last_name = object[0]["last_name"]; cout << first_name << endl; cout << last_name << endl; return 0; }
Вот пример работы

Приведение double к float в C++

Пусть переменная типа double приводится к переменной типа float. Если переменная double хранит значение NaN, то оно преобразуется в NaN. Если переменная double хранит значение Inf, то оно преобразуется в Inf. Если переменная double хранит значение -1e+50, то оно преобразуется в -Inf
Такое поведение гарантируется стандартом C++, или IEEE 754? Или это implementation-defined behavior, или это вообще undefined behaviour и рассчитывать на то, что -1e+50 преобразуется в -Inf вообще говоря не стоит?


Ответ

Строго говоря, стандарт не определяет размерности float и double, но в своём ответе я буду считать, что они разной размерности и представляют собой 32-х и 64-х разрядные типы данных соответственно.
Т.к. float может вмещать в себя числа от ±1.18×10^(−38) до ±3.4×10^38, а Вы пытаетесь вместить в переменную float, переменную типа double, значение которой не может быть представлено во float в точности, Вы получаете -inf. Вы получаете неопределённое поведение. Поэтому надеяться на -inf не стоит.
Первоначальный мой ответ, утверждающий, что получится неопределённое поведение, является неверным. Неопределённое поведение получается, если мы пытаемся поместить во float такое число, которое не может быть в нём представлено. Вот как это описано в стандарте:
Стандарт C++14 [conv.double]
A prvalue of floating point type can be converted to a prvalue of another floating point type. If the source value can be exactly represented in the destination type, the result of the conversion is that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an implementation-defined choice of either of those values. Otherwise, the behavior is undefined.
Но это всё касается абстрактной реализации, а у нас она вполне конкретная (и в этом крылась моя ошибка — я примерил конкретную реализацию к абстрактному описанию и сделал ошибочный вывод). Раз уж я сделал предположение о диапазоне допустимых значений float, я взял конкретную реализацию — IEEE 754. А раз я взял эту реализацию, то и отталкиваться нужно от неё, а не от абстракции.
Согласно IEEE 754 бесконечность является частью типа, а следовательно его максимальные и минимальные значения не являются его ограничителями. Просто всё, что лежит вне допустимого диапазона приводится к нужному значению согласно правилам округления. Так вот, согласно этому правилу, если пытаться представить -1e+50 во float, то получится -INF — это нормальное значение float и оно гарантировано при std::numeric_limits::is_iec559 равным true*. Т.е. мы имеем эту ситуацию из стандарта: «the source value is between two adjacent destination values, the result of the conversion is an implementation-defined choice of either of those values»
Если же вышеозначенная константа равна false, то ответ на вопрос может быть другим, но рассмотрен он тоже должен быть в рамках конкретной реализации, т.к. у нас есть конкретная цифра в вопросе, которую мы не можем рассматривать без конкретики со стороны реализации.
Подводя итог: является ли подобное поведение, неопределённым поведением, зависит ли оно от реализации — всё это зависит от представление типов с плавающей точкой и не может быть рассмотрено вне оного.
* Я не нашёл текста самого документа, но многие документы, ссылающиеся на оный, утверждают это.

В языке C это, кстати, указано более явно: если среда поддерживает бесконечность, то результат определён и с примером из вопроса даст гарантировано -inf. Это описано в стандарте C11 [5.2.4.2.2/p5]
The minimum range of representable values for a floating type is the most negative finite floating-point number representable in that type through the most positive finite floating point number representable in that type. In addition, if negative infinity is representable in a type, the range of that type is extended to all negative real numbers; likewise, if positive infinity is representable in a type, the range of that type is extended to all positive real numbers.

Сложные условия в switch

Есть if, а есть switch. Если использовать if то "или" будет записываться как ( условие | условие ). Можно ли сделать подобное в при помощи switch? Моя кривая интуиция:
int x = 10 switch (x){ case 1| case 2: ... }
Конечно же, можно не парится, и записать это как:
switch (x){ case 1: ... case 2: ... }
...Но такой способ прошу не рассматривать.


Ответ

В примерах кода часто вижу вторую реализацию, скорее всего — это стандарт:
switch (x){ case 1: case 2: ... break; case 3: ... break; }

В комментариях подтвердили, что это стандарт. Вот документация с сайта Oracle — ссылка

Как защитить исходный код?

Нужно сделать так, чтоб apk файл нельзя было прочитать.
Как по мне достаточно стандартная ситуация, но все ссылки которые я нашел ведут сюда
https://developer.android.com/studio/build/shrink-code.html
Но тут описано как сделать обфускацию и все такое, но мне нужно именно как то защитить код от приложений которые могут открывать apk файл и читать весь код
Если я правильно понял то это делается с помощью pro-guard файл , но не могу найти как
Подскажите кто сталкивался


Ответ

DexProtector вам в помощь, стоит конечно 800$, но проверяли в действии. Отдавали реверсерам, никто так и не смог вытащить хотя бы отдаленно читабельные исходы

Остаток от деления числа в большой степени

Как можно быстро вычислить (x^n)mod y. Уже когда-то копал этот вопрос и обнаружил теорему Эйлера (теория чисел). Не относится к вопросу: Но вся проблема в том, что я учусь в школе, и мы не проходили еще подобных выражений, найденных мною на wiki, и теории чисел. Объясните пожалуйста:
Как использовать эту теорему на практике(например, реализация на C). (Не так важно, но просто интересно)Кратко значение формулировки на wiki. Буду рад какой-нибудь статье, etc для тех, кто еще не знаком с теорией чисел и математикой >9 классов.


Ответ

В украинской (также как и в английской и немецкой [остальные не проверял]) версии википедии есть хороший пример использования Теоремы Эйлера
Наприклад ми хочемо обчислити 7222 (mod 10). Маємо, що 7 і 10 є взаємно простими і φ(10) = 4. Одже згідно з теоремою Ейлера 74 ≡ 1 (mod 10) і як наслідок 7222 ≡ 74x55 + 2 ≡ (74)55 x 72 ≡ 155 x 72 ≡ 49 ≡ 9 (mod 10).
Моя попытка перевода:
Например мы хотим вычислить "7222 (mod 10)". 7 и 10 являются взаимно-простыми и φ(10) = 4 (это число натуральных чисел не больших чем 10 и являющихся взаимнопростыми по отношению к 10. Это следующие числа: 1,3,7,9 и всего их 4).
Следовательно согласно теореме Эйлера 74 ≡ 1 (mod 10) и как следствие:
7222 ≡ 74x55 + 2 ≡ (74)55 x 72 ≡ 155 x 72 ≡ 49 ≡ 9 (mod 10).
Следствия из теоремы:
если aφ(n) ≡ 1 (mod n), то и (aφ(n))k ≡ 1 (mod n) для любого положительного k, т.к.
(aφ(n))k ≡ aφ(n) mod n * (aφ(n))k - 1 mod n ≡ (aφ(n))k - 1 (mod n) и т.д.

Код, по-разному работающий в C++03 и C++11/14

Понятно, что изменение смысла auto от одного стандарта к другому приводит к возможности ошибки, или, наоборот, ошибочный из-за >> в шаблоне код становится нормальным.
А есть код, который при переходе от стандарта С++03 к С++11 (ну, или 14) меняет свой смысл? Работает и там и там но дает разные результаты?
Или даже в С++17? Короче, от одного какого-то стандарта к другому?


Ответ

В конце стандарта есть приложение "Совместимость", в котором перечислены все несовместимости с предыдущими стандартами.
Раздел про совместимость текущего стандарта и С++03
Несовместимостей много. Вот первая по списку:
#define u8 "abc" const char* s = u8"def"; // Раньше "abcdef", теперь "def"

Узнать разрядность ОС Windows C++

Здравствуйте, возник вопрос с тем, как узнать разрядность ОС Windows. Пробовал через препроцессинг, но выдает неправильные данные...
#ifdef WIN64 #define OS_BIT 64 #endif // !WIN64
#ifdef WIN32 #define OS_BIT 32 #endif // !WIN32
Может быть есть какой-нибудь другой способ?


Ответ

BOOL Is64BitWindows() { #if defined(_WIN64) return TRUE; // Программа скомпилирована для x64 #elif defined(_WIN32) // Программа скомпилирована для x32, спрашиваем ОС BOOL f64 = FALSE; return IsWow64Process(GetCurrentProcess(), &f64) && f64; #else return FALSE; // Программа скомпилирована для x16 #endif }
Источник: https://blogs.msdn.microsoft.com/oldnewthing/20050201-00/?p=36553/

Как программно узнать версию exe?

В свойствах файла есть поле "Версия файла". Как программно получить версию?


Ответ

Используйте FileVersionInfo.FileVersion
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(@"C:\asdf.dll ");
Пример.
Исходный файл в проводнике:

Данные полученные программным путём:

Как парсить html страничку с JavaScript в python 3?

Как парсить html страничку с JavaScript в python 3 и что для этого нужно.


Ответ

Чтобы достать статические данные из html, javascript текста, можно использовать соответствующие парсеры, такие как BeautifulSoup, slimit. Пример: Как, используя Beautuful Soup, искать по ключевому слову если это слово находится в теге script?
Чтобы получить информацию с web-странички, элементы которой javascript динамически генерирует, можно web-браузером воспользоваться. Чтобы управлять разными браузерами из Питона, selenium webdriver помогает: пример с показом GUI. Есть и другие библиотеки, к примеру: marionette (firefox), pyppeteer (chrome, puppeteer API для Питона) — пример получения снимка экрана с web-страницей с использованием этих библиотек. Чтобы получить html страницу, не показывая GUI, можно «безголовый» (headless) Google Chrome запустить и с использованием selenium:
from selenium import webdriver # $ pip install selenium
options = webdriver.ChromeOptions() options.add_argument('--headless') # get chromedriver from # https://sites.google.com/a/chromium.org/chromedriver/downloads browser = webdriver.Chrome(chrome_options=options)
browser.get('https://ru.stackoverflow.com/q/749943') # ... other actions generated_html = browser.page_source browser.quit()
Этот интерфейс позволяет автоматизировать действия пользователя (нажатие клавиш, кнопок, поиск элементов на странице по различным критериям, итд). Анализ полезно на две части разбить: загрузить из сети динамически генерируемую информацию с помощью браузера и сохранить её (возможно наличие избыточной информации), а затем детально анализировать уже статическое содержимое, чтобы изъять только необходимые части (возможно без сети в другом процессе с помощью того же BeautifulSoup). К примеру, чтобы найти ссылки на похожие вопросы на сохранённой странице:
from bs4 import BeautifulSoup
soup = BeautifulSoup(generated_html, 'html.parser') h = soup.find(id='h-related') related = [a['href'] for a in h.find_all('a', 'question-hyperlink')]
Если сайт предоставляет API (официальное или подсмотренное в сетевых запросах выполняемых javascript: пример для fifa.com), то это может быть более предпочтительным вариантом по сравнению с выдёргиванием информации c UI элементов web-страницы: пример, использования Stack Exchange API
Часто можно встретить REST API или GraphQL API, которые удобно с помощью requests или специализированных библиотек использовать (по ссылкам примеры кода для github api).

Как создать pattern или path цепи вдоль линии

Мне необходимо создать pattern цепи расположенный вдоль линии . Я попытался создать markers в форме звена цепи, но возникли проблемы с ориентацией маркеров вдоль path.
Есть ли альтернативный способ сделать это? Если да, то каким должен быть мой подход?
Ожидаемый результат - что-то вроде этого:
Источник


Ответ

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

Пример кода:

Но вдоль пути будет двигаться только один предмет, то есть одно звено цепи. Чтобы разместить несколько десятков звеньев цепи, нужно будет десятки раз повторить эту команду и нет способов, как оптимизировать код. Плюс неизбежно появятся трудности с позиционированием и склейкой соседних звеньев.
Для размещения текста вдоль криволинейного пути, в SVG существует другая команда -
O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-O-
Update
В примере выше использована идея из ответа Enso @Michael Mullany
Но цепочка выглядит совсем не так, как хотелось.
А если заменить буквы на символы Юникодов, которые более реалистично имитируют звенья цепи?
Я остановился на варианте использования символа Юникода - "Латинская маленькая буква на боку" - U+1D11 ᴑ и знак дефиса для соединения соседних звеньев цепи - -
- - - - - - - - - -
, где
ᴑ - символ Юникода, латинской O на боку.
dx="-15" - смещение этого символа влево.
В дополнении пример анимации
- - - - - - - - - -
Источник ответа: How can I draw a pattern along a stroke or a path in svg? @Alexandr_T
Связанный топик - Использование символов Юникода в анимации

Чем отличается codePointCount от substring().length()?

Привет всем. В Java у строки есть метод codePointCount. Его можно записать так?
String s = "Hello, string!"; System.out.println(String.valueOf(s.codePointCount(0, 5)); System.out.println(String.valueOf(s.substring(0, 5).length());
Зачем вообще считать количество символов если можно просто отнять от второго аргумента первый
5 - 0 = 5
Или я что-то не так понял?


Ответ

Разница проявится при появлении в строке символов, представимых более чем одним 16-битным блоком (code unit). Так как length возвращает количество 16-битных блоков, а codePointCount - именно символов.
Например, эмодзи состоят из пары 16-битных блоков, так как их код в таблице Unicode больше U+FFFF.
String s = "😀"; System.out.println(s.length() + " " + s.codePointCount(0, 2)); // 2 1
Соответственно, длина строки s будет 2, но символ в ней только один.

Получить ноды в блоке div

Есть примерно такой костяк разметки :

//...

Как мне получить и изменить атрибут одного из input ?
UPD - блок div при первой загрузке страницы всего один. Однако по нажатию ЛКМ на кнопку в документ добавляется еще один. В новом блоке div нужно поменять Educations[0].Facultet на Educations[1].Facultet. И в каждом новом div счетчик должен увеличиваться на 1. Новый блок div добавляется так :
var non_ness = document.getElementById('not_necessery_prop'); var cloneNotNess = non_ness.cloneNode(true); maindiv.appendChild(cloneNotNess);


Ответ

function showInputValues() { var v3 = document.querySelector("input[name='Educations[3].Facultet']").value; var v1 = document.querySelector("input[name='Educations[1].Facultet']").value; var v0 = document.querySelector("input[name='Educations[0].Facultet']").value; console.log(v0, v1, v3); }


Проверка содержимого буфера обмена

Как можно проверить содержит ли буфер обмена текст, картинку или ссылку?


Ответ

Есть класс Clipboard, этот класс позволяет работать с буфером обмена.
Пример проверки данных в буфере:
// After this line executes, IsHTMLDataOnClipboard will be true if // HTML data is available natively on the clipboard; if not, it // will be false. bool IsHTMLDataOnClipboard = Clipboard.ContainsData(DataFormats.Html);
// If there is HTML data on the clipboard, retrieve it. string htmlData; if(IsHTMLDataOnClipboard) {
htmlData = Clipboard.GetText(TextDataFormat.Html);
}
Так же есть методы ContainsImage и ContainsText, которые проверяют наличие картинки или текста в буфере обмена.

Получение списка ограничивающих прямоугольников для объектов SVG

Есть нарисованный рисунок в SVG. Для моей задачи нужно получить список ограничивающих прямоугольников объектов (например, идентификатор, координаты угла прямоугольника, ширина, высота, задающие параметры прямоугольника). Есть ли возможность сделать это автоматизированно, чтобы вручную не выписывать эти параметры?
На рисунке нужные прямоугольники показаны прерывистой линией:
image/svg+xml


Ответ

Нашёл ответ, который меня устроил - я смог получить те координаты ограничивающих прямоугольников, которые я вижу в редакторе Inkscape. Как ни странно в этом помогла сама программа Inkscape, а точнее - возможности программы в режиме командной строки. У этого режима много параметров, но для решения моего вопроса пригодился единственный - это "--query-all".
Например, имя файла с рисунком - example.svg.
Порядок действий такой:
Запускаем режим командной строки операционной системы; Переходим в папку, где лежит рисунок; Выполняем команду для Windows(путь к файлу inkscape.com уточняйте для своей системы):
"C:\Program Files\Inkscape\inkscape.com" example.svg --query-all>example.txt
для Ubuntu:
inkscape example.svg --query-all>example.txt
В результате нужная информация будет выведена в файл example.txt. Вот содержимое файла, который я получил в результате этой операции (кажая строчка в формате id,X,Y,ширина,высота):
Windows:
svg8,28.521432,73.716034,263.00711,270.66968 layer1,28.521432,73.716034,263.00711,270.66968 rect816,161.42855,232.85714,130.1,111.52857 path818,28.521432,252.90715,61.528569,67.242858 path820,82.402299,73.716034,177.81245,132.3059
Ubuntu:
svg8,26.738842,69.108782,246.56917,253.75282 layer1,26.738842,69.108782,246.56917,253.75282 rect816,151.33927,218.30357,121.96874,104.55804 path818,26.738842,237.10046,57.683033,63.040179 path820,77.252155,69.108782,166.69917,124.03678
Размеры объектов на первый взгляд получились различными и в непонятных единицах, но для вывода использовались разные версии Inkscape, а Inkscape недавно перевели с разрешения 90 dpi на разрешение 96 dpi. Я понял, что это цифры в пикселях с соответствующим разрешением.
Пересчитаем координаты и размеры в мм для windows и ubuntu, взяв разрешения 96 и 90 соответственно. Считаем по формуле Xmm=Xpix/dpi*25.4.
Windows:
svg8,7.54629555,19.504034,69.58729785,71.61468617 layer1,7.54629555,19.504034,69.58729785,71.61468617 rect816,42.71130385,61.61011829,34.42229167,29.50860081 path818,7.54629555,66.91501677,16.27943388,17.79133951 path820,21.80227494,19.504034,47.04621073,35.00593604
Ubuntu:
svg8,7.546295409,19.50403403,69.58729909,71.61468476 layer1,7.546295409,19.50403403,69.58729909,71.61468476 rect816,42.71130509,61.61011864,34.42228884,29.5086024 path818,7.546295409,66.91501871,16.27943376,17.79133941 path820,21.80227486,19.50403403,47.0462102,35.00593569
Получились практически идентичные значения, различающиеся только с 6-го знака после плавающей точки. Но здесь координаты - с началом отсчёта от верхнего левого угла листа и осью Y направленной вниз.
Чтобы получить координаты объектов, как их показывает InkScape (ось Y направлена вверх, отсчёт от нижнего левого угла листа), нужно Y заменить результатом вычитания Y и высоты объекта из высоты листа (высоту листа можно посмотреть в редакторе, в самом файле SVG, либо добавить прямоугольник, ограничивающий лист. В последнем случае высоту листа можно будет найти в первой строчке вывода).
Я взял высоту листа из диалогового окна. И в результате получил значения, которые показывает InkScape, учитывая что он округляет до 3-го знака после запятой.
svg8,7.54629555,6.047619838,69.58729785,71.61468617 layer1,7.54629555,6.047619838,69.58729785,71.61468617 rect816,42.71130385,6.047620896,34.42229167,29.50860081 path818,7.54629555,12.45998372,16.27943388,17.79133951 path820,21.80227494,42.65636996,47.04621073,35.00593604

Как реализовать эффект появления фото?

Увидел эффект с фото но ради профессионального интереса не стал открывать "просмотр кода" и решил сам реализовать, то что на скриншоте :

Мне удалось, так реализовать, как в примере ниже, но мне кажется, что решение не очень красивое! Можно ли это, как-то по другому сделать?
body, html { height: 100%; margin: 0; padding: 0; background: #E3DFD2 }
svg { background: url('http://www.frombearcreek.com/wp-content/uploads/2016/07/2016_07_15_Rule-Five-Friday-1-1024x683.jpg'); background-size: cover; width: 40vmin; height: auto; display: block; margin: 30vmin auto; }
text { font-size: 10px; transition: font-size .4s ease-out; font-weight: 900; font-family: arial; }
svg:hover text { transition: font-size .4s ease-in; font-size: 600px; }

s e e


Ответ

Вот более чистая версия:
body, html { height: 100%; margin: 0; padding: 0; background: #E3DFD2 } svg { background: url('http://www.frombearcreek.com/wp-content/uploads/2016/07/2016_07_15_Rule-Five-Friday-1-1024x683.jpg'); background-size: cover; width: 40vmin; height: auto; display: block; margin: 30vmin auto; } text { font-size: 10px; transition: font-size .4s ease-out; font-weight: 900; font-family: arial; letter-spacing: -1px; } svg:hover text { transition: font-size .4s ease-in; font-size: 600px; } see

Как сверстать круглый блок с иконками внутри?

Подскажите, пожалуйста, как сверстать такое расположение иконок? Если приглядеться, там по окружности (белый фон с несколькими кругами) расположены кликабельные иконки...
У меня вообще нет идей.


Ответ

Добавляю новый ответ, так как приложение почти полностью переписано и не знаю какое решение больше устроит автора.
Что сделано вновь:
Все изменяемые параметры переведены в проценты для достижения полной адаптивности. Блок окружностей, который обеспечивает круглую основу иконки с тенью переведен в секцию для многократного использования с помощью команды Упрощена формула фильтра, который размывает тень Убраны фиксированные значения widthи height из шапки SVG для получения адаптивности svg код обернут в

, что позволит менять размеры svg блока, меняя проценты ширины и высоты родительского
. Добавлены ссылки на каждую иконку Иконки распределены по всей ширине svg блока
Для настройки размера и интенсивности тени увеличивайте или уменьшайте радиусы двух окружностей относительно друг друга. Так же для этих целей, можно изменять атрибут stdDeviation="4" фильтра
.container { width:100%; height:100% }

Прозрачная кнопка на Android

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


Ответ

Создайте новый xml файл в res/drawable и после добавьте свойство background c именем созданного файла.
gradient.xml

layout.xml

Как явно задать тип для значения NULL в SELECT?

Eсть таблица со столбцами COL_1 number, COL_2 number, запрос целиком:
SELECT * FROM TABLE_1
И есть представление:
CREATE VIEW V1 AS SELECT NULL AS COL_1, TABLE_2.COL AS COL_2 FROM TABLE_2
Хочу их объединить:
SELECT * FROM TABLE_1 union all SELECT * FROM V1
И получаю ошибку - выражения не соответствуют друг другу, ожидалось NULL, в представлении имеет тип varchar2.
Но я не просил его быть текстовым. Как явно задать тип?


Ответ

Надо столбцы привести к одному типу. Например для:
create table table_1 (col_1 number(10), col_2 number); create table table_2 (col number);
будет так:
CREATE VIEW V1 AS SELECT CAST (NULL AS number(10)) AS COL_1, TABLE_2.COL AS COL_2 FROM TABLE_2 ;
Функция CAST сконвертирует NULL, по умолчанию VARCHAR2(0), в тип данных, указанный во втором операнде.
Тот же результат возможно также достигнуть функцией to_number(null), но только если нет необходимости ограничения по длине (т.н. non-constrained type). То есть, например:
cast (null as number(10)) ... -- user_tab_cols.data_precision=10 to_number (null) ... -- user_tab_cols.data_precision=null
Подробнее в документации

Сохранение файла от имени пользователя C#

Вопрос: Можно ли сохранить файл в сетевую директорию используя учетную запись другого пользователя?
Подробности: Есть служба, работающая под учетно записью System. Служба, кроме прочего, занимается синхронизацией со сторонним сервисом из которого нужно выкачивать файлы и складывать в сетевую папку. Но у System нет прав доступа к сетевой папке. Зато служба знает логин/пароль пользователя, у которого такие права есть.
(Пока видится только сохранение файла в temp и запуск копирования через Process.Start, но может быть есть что-то более элегантное?)


Ответ

Вы можете выполнить код внутри своего процесса от другого пользователя. Сначала импортируем WinAPI функцию LogonUser
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool LogonUser( string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
А дальше вот так:
IntPtr token; if (LogonUser("SomeUser", "SomeDomain", "SomePwd", 2, 0, out token)) { var identity = new WindowsIdentity(token); using (identity.Impersonate()) { // здесь вы можете убедиться, что код выполняется под другим юзером Console.WriteLine(Environment.UserName); // делаем что-то File.WriteAllText(@"path.txt", "hello!"); } } else { Console.WriteLine("Invalid credentials"); }

Почему нельзя использовать StreamReader вместе с NetworkStream?

В книге Албахари "C# 6.0 in a Nutshell" написано следующее:
В действительности класс StreamReader абсолютно запрещено применять вместе с NetworkStream, даже если вы планируете вызывать только метод ReadLine. Причина в том, что класс StreamReader имеет буфер опережающего чтения, который может привести к чтению большего числа байтов, чем доступно в текущий момент, и бесконечному блокированию (или до возникновения тайм-аута сокета). Другие потоки, такие как FileStream, не страдают подобной несовместимостью с классом StreamReader, потому что они поддерживают определенный признак окончания, при достижении которого метод Read немедленно завершается, возвращая значение 0
Какая ошибка, например, в этом классе?
public class AsyncSocket : IDisposable { Socket socket; StreamReader sr;
public AsyncSocket() { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sr = new StreamReader(new NetworkStream(socket)); }
// ... остальные члены убраны
public async Task ReadLineAsync() { return await sr.ReadLineAsync(); }
public void Dispose() { if (sr != null) sr.Close(); if (socket != null) socket.Dispose(); } }
Допустим, пришла строка "123
qwe". StreamReader считает всю её в свой внутренний буфер при вызове ReadLineAsync() вернет "123". Данные из внутреннего буфера не удаляются же? При втором вызове ReadLineAsync() завершится, когда придет конец строки и в результатом вернется "qwe". Албахари пишет про бесконечное блокирование, так к нему может привести и обычный метод Read, если никакие данные не будут отправлены сокету.
Объясните почему нельзя использовать класс StreamReader вместе с NetworkStream?


Ответ

"Буфер опережающего чтения" означает, что StreamReader попытается вычитать из потока сразу килобайт (bufferSize) данных. "Про запас". Это улучшает производительность в случае чтения с диска, но может приводить к непредсказуемым последствиям при чтении.
Особенность NetworkStream.Read в том, что он может блокироваться при чтении (в случае, если сокет еще открыт, но данных нет).
Албахари пишет о теоретической ситуации, когда
StreamReader мог бы вернуть вам данные (т.к. они есть в буфере), но обнаружил, что в буфере есть место и решил на всякий случай дочитать побольше данных в буфер вызвал NetworkStream.Read NetworkStream.Read заблокировался
И вы оказываетесь в ситуации, когда вроде как нужные вам данные пришли, но StreamReader висит и не возвращает ничего, т.к. хочет еще больше данных из потока.
На практике (в текущей реализации StreamReader и NetworkStream) такая ситуация не возникает, т.к.
StreamReader читает данные из входного потока только в случае, если в буфере недостаточно данных для завершения требуемой операции. NetworkStream.Read не блокируется, если хоть какие-то данные есть.
Т.е. блокировка произойдет только в случае, когда нужные данные действительно не пришли.
Но реализация — это одно, нет никаких гарантий что она не поменяется.
На самом деле проблема решается тем, что сочетание NetworkStream + StreamReader не имеет практической ценности. StreamReader приспособлен для работы с чисто текстовыми данными. Например, он пытается искать в читаемом потоке преамбулу (BOM), и вообще — использует сами данные для определения концов строк, что уже дико неудобно при работе с сетью.
По сети обычно передаются смешанные данные. Например, те же строки принято передавать в виде <длина><текст>, чтобы не попадать в ловушку "непонятно сколько данных вычитали и сколько еще ждать". Для такой работы со стримами удобнее использовать BinaryReader

Как сделать поисковый сниппет на Javascript?

Javascript. Есть массив со статьями. По ним происходит поиск через indexOf.
Как сделать сниппет аля гугл? То есть брать первое вхождение в строке и выдергивать несколько слов справа и слева?
Например ищем слово file в строке:
Edit config.toml and change the default properties to suit your own information. This is not required to run the example, but this is the global configuration file and you're going to need to use it eventually. Start here!
In a command prompt or terminal, navigate to the path that contains your config.toml file and run hugo. That's it! You should now have a public directory with a complete blog! Open public/index.html in your browser and bask.
If that wasn't amazing enough, from the same terminal, run hugo server. This will watch your directories for changes and rebuild the site immediately, and it will make these changes available at http://localhost:1313/ so you can view your finished site in your browser. Go on, try it. This is one of the best ways to preview your site while working on it.
И получить сниппет:
...global configuration file and you're...


Ответ

Можно так, как вариант:
var str = 'navigate to the path that contains your config.toml file and run hugo';
console.log(snippet(str, 'file'));
function snippet(stringToSearch, phrase) { var regExp = eval("/(\\S+\\s){0,3}\\S*" + phrase + "\\S*(\\s\\S+){0,3}/g") return stringToSearch.match(regExp); }

В чем различие Scanner, Console и BufferedReader?

Объясните, в чем различие для ввода данных в консоли Scanner, Console и BufferedReader bReader = new BufferedReader (new InputStreamReader(System.in)); и какой лучше из них использовать?


Ответ

Различие простое Scanner предназначен для разбора любого текста и, ввода с терминала, как частный случай. Он умеет выцеживать числа всякие и т.п. Удобен для простого разбора текстов и для всяких учебных задачек типа "введите число от нуля до трёх". Console нужен для вводы именно с консоли, но иногда это не работает: иногда нет консоли и тогда никак не воспользоваться этой штукой. Консоль не умеет ничего парсить, а только обеспечивать ввод, в том числе безопасный ввод пароля. BufferedReader нужен, чтобы буфферизовать чтение с любого потока. Как частный случай, можно буфферизовать ввод с терминала. Иногда используется ради метода readLine, когда сложно или просто день обрабатывать текст блоками. Для целей чтения текста из стандартного вводы или ручного ввода пользователя вполне пригодный вариант. Но при таком подходе придётся парсить числа вручную, что не слишком большая сложность. Сказать какой использовать вам никто не может. Это зависит от задачи и условий выполнения. Если данные поступают через стандартный ввод, то вероятно следует ожидаать, что Console вас подведёт. Scanner полезен, но он может оказаться слишком полезен и сильно всё затормозить, если данных очень много. Буфферизованный ввод тоже может подсунуть вам бяку, так что в любом случае следует рассматривать источник данных, объём данных и их характер, чтобы принять какое-то решение.

Запрет перетаскивания img и url браузером

Во многих браузерах (например в хроме и ие) возможно "перетащить" картинку или ссылку, зажав над ней левую кнопку мыши, допустим в адресную строку и т.д.. Требуется с помощью js запретить. Каким образом это возможно реализовать? (написан маленький скрипт, позволяющий зажав кнопку над элементов свободно перетаскивать его. Проблема в том, что если элемент - картинка, вместо перетаскивания, браузер (хром, ие и т.д. кроме опера) захватывает его по своему, для переноса в адресную строку, на панель и прочее. Надо как-то запретить браузеру его действие по умолчанию) p.s. -webkit-user-select: none; -moz-user-select: none; проблемы не решают


Ответ

el.onmousedown = function (e) { if (window.event.stopPropagation) window.event.stopPropagation(); window.event.cancelBubble = true; e.cancelBubble = true; } Поидее должно помочь

Стоит ли изучать Ruby или сразу начинать c Ruby on Rails [закрыт]

Всем привет! Дорогие друзья, стоит ли изучать Ruby или стоит сразу перейти к RoR, тяжело ли будет сразу начать с RoR?


Ответ

Обычно соваться использовать фреймворк без хорошего знания языка -- плохая затея, но в случае с Rails всё немного иначе. Дело в том, что в самом фреймворке очень часто используются DSL, и для их использования знание Ruby не сильно важно (лишь синтаксис). По-моему мнению, можно сразу начинать изучать Ruby on Rails даже если нет твёрдых знаний Ruby. Хотя конечно без них не обойтись в реальной разработке.

В чем разница вызовов(обьявлений) этих обьектов?

Добрый вечер, начал изучать js около месяц назад, начал с видеокурсов Специалист. В общем там обьекты обьявлялись и вызывались такими вот способами: 1) var iamobj=new Object; iamobj.name="giggity"; iamobj.show=function(){ alert(this.name); }
iamobj.show(); ну здесь понятно, обьявили обьект, обьявили свойство и метод, затем вызвали метод 2) function Test(name){ this.name=name; this.show=function(){ alert(this.name) } }
var iamobj=new Test("giggity"); iamobj.show(); что имеем здесь: снизу обьявили обьект и сразу-же присвоили ему функцию, куда передали значение, затем вызвали метод Здесь вроде бы как все понятно, не ясно только какой метод когда лучше использовать.. но затем начал вчитываться в статью про свойства и методы обьектов на javascript.ru и вообще запутался синтаксис совершенно другой.. сейчас покажу 3) var iamobj={ read:function(){ this.name=prompt("имя?") }, show:function(){ return this.name } }
iamobj.read(); alert(iamobj.show()) собственно.. вопрос.. что это вообще такое и зачем? внизу сразу вызывается метод у обьекта iamobj, потом поднимаемся вверх и только тут обьявляем обьект (var), считываем значения имени в методе.. и снизу вызываем еще один метод чтобы показать. между методами в обьекте обьязана стоять запятая.. зачем столько вариатов обьявлений? у каждого из них есть какое-то преимущество в определенном условии? 4) function show(){ this.name=name; alert(this.name); }
var iamobj=new show("giggity") снизу обьявили обьект, тут же вызвали ф-цию и передали в нее значение, та берет значение, присваивает и выводит.. легкий способ, но опять же, синтаксис другой 5) function iamobj(){ this.show=function(){ var a=prompt("name?") alert(a); } }
new iamobj().show(); опять же новый синтаксис, внизу обьявляем обьект и тут же пишем какой метод в нем хотим вызвать, обьект являетсо функцией(?), внутри которого каждое свойство = метод (так чтоли? зачем?) в общем, обьясните кто-то пожалуйста зачем столько вариантов разных есть и в чем преимущество каждого? хотя бы приблизительно, ато я что-то вообще уже теряюсь


Ответ

Столько возможностей объявления для нашего с вами удобства, правда что касается примера инициализации объекта с помощью ключевого слова new - это нечто иное, если быть точным то это одна из возможных реализаций ООП, раз уже задел этот вопрос - немного о концепции. Любая функция может вызываться при помощи оператора new, функция, далее конструктор, которая вызывается при помощи оператора new получает на вход переменную this которая является еще не созданным объектом (который она, собственно и вернет), в контексте ООП - экземпляром "класса". Не смотря на похожий синтаксис - ООП в javascript устроено не так как везде, если быть более точным - построено на прототипировании. Теперь непосредственно о прототипах - у любой функции есть прототип (если быть точным у любого объекта, но в нашем случае речь не об этом), прототип это объект к которому имеют доступ все экземпляры конструктора("класса") ( сам по себе он всего-лишь JavaScript объект ), в котором целесообразно хранить общие методы или свойства для всех экземпляров конструктора("класса"). Что же касается специфических свойств и методов - их необходимо (читай по хорошему) инициализировать в конструкторе. Важно добавить - prototype это 1 единственный объект, независимо от количества экземпляров, соответственно, если, например, писать так: var User = function( username ) { this.__username = username; this.getUsername = function(){ return this.__username; } this.setUsername = function( username ){ this.__username = username; } }
var user1 = new User('Vasya'); var user2 = new User('Petya'); В этом случае - методы getUsername и setUsername делают одну и ту-же работу, но, что касаемо памяти - это разные функции, в этом можно легко убедиться: alert( user1.getUsername === user2.getUsername ) // false alert( user1.setUsername === user2.setUsername ) // false Соответственно с точки зрения памяти и вообще здравого смысла - этот подход не лучшее решение. Но теперь о том как все это нужно делать в javascript'e, перепишем пример var User = function( username ) { this.__username = username; } User.prototype = { getUsername : function(){ return this.__username; }, setUsername : function( username ){ this.__username = username; } }
var user1 = new User('Vasya'); var user2 = new User('Petya');
alert( user1.getUsername === user2.getUsername ); // true alert( user1.setUsername === user2.setUsername ); // true Как мы видим - использовав прототип мы добились того что наши методы getUsername и setUsername не плодятся для каждого вызова конструктора, а инициализируются единожды, что уже совсем другое дело с точки зрения памяти и здравого смысла. Ну а что касаемо разницы между записями вида var obj;
obj = {}; obj.somePropName = someValue; // ........
obj = { somePropName : someValue, // ........ };
obj = new Object(); obj.somePropName = someValue; // ........ Отличия нет, по крайней мере с точки зрения производительности. Есть разница только с точки зрения работы геттеров и сеттеров в контексте глобального конструктора Object, но я не думаю что вам это принципиально. По поводу последнего примера, на самом деле, грубо, происходит следующее: function iamobj(){ this.show=function(){ var a = prompt("name?") alert(a); } }
// new iamobj().show(); var obj = new iamobj(); obj.show(); Точно так-же мы могли бы поступить, например, с DOM элементом: document.getElementById("someElementId").onclick = function(){ /* observer code here... */ } С точки зрения целесообразности - применимо только в том случае, если объект не будет использоваться далее, и даже не смотря на это Крокфорд (и я за компанию), все-же, советуют заранее объявлять переменные перед тем как с ними работать. Если вам нужен статический метод, то просто используйте объект без вызова функции в контексте конструктора с помощью new (что-то типа iamobj.show = function(){/*...*/}, iamobj.show()). Вообще надо понимать что и для чего используется, если отбросить new и все из него выплывающее - объект это всего-лишь хэш, то что в объекте могут храниться функции - особенность языка, то что функции хэша имеют доступ в теле функции к хэшу через перменную this - так-же особенности языка, благодаря им можно городить пространства имен и легко и без напряга писать singleton'ы (и многое другое), но, как-бы там не было - в своем элементарном проявлении это всего-лишь ассоциативный массив. Надеюсь этой информации достаточно, пожалуй прекращаю т.к. и так ответ "немного" растянулся.