Проверить какие ветви мерджились

В процессе работы с Git через некоторое время вывод -a оказывается сильно захламленным (если не делать своевременные чистки). Это более заметно если работает не один человек, а целая команда. В таких случаях время от времени необходимо делать генеральную уборку, но сложность заключается в том, что определить какие ветви можно удалить, а какие нет  становится сложновато. Для этого можно просто проверить основную ветвь (обычно это master):

& git checkout master
& git branch --master

чтобы увидеть какие ветки уже мерджнуты в основную (в данном случае master).

В некоторых случаях нужно выполнить обратное (то есть исключить из списка какую-то ветвь):

& git branch --no-master

Как насчет удалить все устаревшие ветви?

& git branch --merged | xargs git branch -d

Как альтернативу можно использовать метод Pull GitHub’а в случае если этим пользовались частенько.

Опубликовано в Git

Как писать кроссплатформенные Cordova 3.3 приложения для iOs и Android

Эта статья пригодится тем, кто собирается писать приложения для iOs7 или Android в Cordova 3.3

В статье описываются такие моменты как:

  • Настройка среды Cordova 3.3 для создания приложений под iPad, iPhone и Android.
  • Настройка командной оболочки bash для взаимодействия с Cordova.
  • Установка и настройка полезных плагинов для Cordova, таких как Splash Screen и In App Browser.
  • Использование Cordova CLI для установки и настройки плагинов.
  • Упаковка и распространение Ваших Android и iOs приложений.

Настройка окружения Cordova.

У Cordova есть несколько важных команд, которые помогут Вам сэкономить время. Для приложений, которые планируется использовать на разных платформах, необходимо наличие нескольких общих файлов JavaScript, CSS, HTML(таких как например config.xml). В остальных случаях каждое приложение использует исключительно свои файлы(как в версиях плагинов для разных платформ).

Эта статья предполагает, что у Вас уже установлено ниже приведенное:

 

итак…

Установка Cordova.

Эта операция подразумевает, что у Вас уже установлен Node Package Manager. Если нет, то пройдите по ссылке(http://nodejs.org/) и установите его.

Теперь откройте терминал и выполните команду:

sudo npm install -g cordova

Теперь Cordova установлена, перейдите в целевую папку и выполните команду:

cordova create TestApp com.YourCompany.yourapp TestApp

Примечание: если планируется в дальнейшем распространять приложения через AppStore, то следует указывать название приложения и Вашей компании вместо com.YourCompany.yourapp.

Перейдите в созданный каталог «TestApp» и добавьте обе платформы(Android и iOs):

cordova add android
cordova add ios

Примечание относительно путей Android.

Если Cordova не в состоянии обнаружить Android SDK, тогда может понадобиться обновить пути(ниже приведенные строки должны указывать на корневую папку Andriod SDK):

open .profile
_______________________________
export ANDROID_HOME=/Users/YOURUSERNAME/android-sdks/
export PATH=/Users/YOURUSERNAME/android-sdks/platform-tools:/Users/YOURUSERNAME/android-sdks/tools:$PATH

После чего запустите команду:

source ~/.profile

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

Команды Cordova CLI, которые необходимо знать.

Есть несколько команд, которые необходимо усвоить для продолжения работы с Cordova.

prepare — копирует основную структуру приложения в определенный платформой каталог:

cordova prepare

build — подготавливает и компилирует приложения:

cordova build

compile — компилирует приложение:

cordova compile

Примечание: Cordova автоматически копирует все вэб и конфиг файлы из папки WWW в папки для каждой платформы(Android/iOs). Если Вы редактируете файлы в папке /platform/ , то будете разочарованы увидев их перезаписанными.

Установка и удаление плагинов для Cordova.

Синтаксис добавления и удаления плагинов очень прост. Для дальнейшей работы нам необходимо добавить плагин Splash Screen и In App Browser. Также необходимо добавить плагин console для возможности просмотре консольного вывода логов в iOs/XCode:

cordova plugin add org.apache.cordova.splashscreen
cordova plugin add org.apache.cordova.inappbrowser
cordova plugin add org.apache.cordova.console

Синтаксис удаления выглядит следующим образом:

cordova plugin remove org.apache.cordova.console

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

Иконки, заставки и наборы картинок.

Для создания иконок я рекомендую использовать ресурс http://makeappicon.com/. Чтобы ознакомиться с инструкциями по работе с картинками в Cordova перейдите по ссылке: http://docs.phonegap.com/en/3.3.0/config_ref_images.md.html#Icons%20and%20Splash%20Screens Генератора для создания заставок я пока не нашел.

Запуск Вашего приложения.

Когда запущен симулятор Genymotion используйте команду «cordova run android» для запуска своего приложения в режиме эмуляции Android. Такая же команда запустит приложение в режиме iOs «cordova run ios». Также можно использовать команду «cordova emulate».

Сборка и дистрибуция исполняемых приложений для Android с Cordova.

Чтобы собрать отлаженный пакет APK(Android Package) для приложения под Android перейдите в папку platforms/android и выполните команду «ant build». Перед тем как выполнить это, убедитесь, что прежде была использована команда «cordova build».

Выполнение этой команды может пройти с ошибками в том случае, если не были правильно скорректированы пути Android SDK.

Если планируется распространять приложение через TestFlight, то необходимо внести некоторые изменения в файл AndroidManifest.xml. А конкретно, открыть его и изменить флаг «debuggable» в false. Также необходимо использовать команду «ant release» для сборки APK.

Сборка и дистрибуция приложений для iOs.

Для сборки по iOs необходимо зайти в каталог приложения (platforms/ios) и собрать XCode как обычно делается. В этом ничего сложного нет.

Опубликовано в Новости

Bootstrap v3.1.0

Сегодня обновился Bootstrap, популярный фреймворк для разработки front-end, до версии v3.1.0

В новой версии добавлены новые шаблоны ( docs/examples/ ):

Bootstrap Blog
Bootstrap blog

Bootstrap Cover
Bootstrap cover

Bootstrap Dashboard
Bootstrap dashboard

* Добавлен новый класс «info» для таблиц.
* Классы .active, .success, .warning, .danger теперь можно использовать для list-group-item элементов
* Для ускорения разработки с использованием модальных окон добавлены классы размеров .modal-lg и .modal-sm
* Для выделения ввода, который обычно осуществляется клавиатурой, добавлен <kbd>
* Добавлены классы для анимации .animation(@animation)
* Добавлены соответствующие прочим, цвета background-color: bg-primary, bg-success…
* Добавлен класс .text-justify
* Добавлен новый form-control для отображения иконок стадий валидации ввода (.has-warning, .has-feedback, .has-error)

Скачать новую версию bootstrap, как обычно, можно здесь

Метки: , ,
Опубликовано в JavaScript, Новости

Отмена последнего коммита в Git

Чтобы понимать как работать с описанными в этой статье методами, необходимо для начала объяснить некоторые вещи.

Что такое HEAD?

HEAD это по сути указатель на последний коммит. После очередного коммита HEAD переключается в конец ветви.

HEAD^ означает ближайшего родителя объекта. Таким образом HEAD^^^ указывает на прадеда.

HEAD~n  указывает на родителя n, то есть HEAD~2 эквивалентно HEAD^^ и ссылается на деда текущего коммита.

А теперь первый способ : Hard Reset — полностью отменяет последний коммит и все сделанные им изменения.

git reset --hard HEAD~1

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

git_hardReset_A

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

git_hardReset_B

Второй вариант: Отмена коммита с сохранением изменений.

Выглядит этот способ следующим образом:

git reset HEAD~1

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

git_Reset

В обоих случаях HEAD указывает на последний коммит. Когда мы выполняем git reset HEAD~1 тогда Git перемещает указатель HEAD на один коммит назад. Но(в отличии от случая с применением —hard) мы оставляем файлы как они есть.

Опубликовано в Git

Как правильно убивать процессы в linux

Почему для уничтожения процессов в Linux не стоит использовать привычный всем «килл-минус-девять» ?
Дело в том что эта команда посылает процессу сигнал SIGKILL, что вызывает его немедленное завершение.
Этот сигнал невозможно перехватить или обработать, потому процесс просто не имеет возможности выполнить какие-либо действия перед смертью. (единственным исключением является процесс init — ему плевать)

Что такого важного должны перед остановкой сделать процессы? Освободить ресурсы. Закрыть дескрипторы, соединения с базами данных, оповестить возможных клиентов, закрыть соединения, удалить временные файлы и так далее..

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

1. Отправьте процессу 15-ый сигнал «SIGTERM» ( kill -15, или kill -TERM, или kill -s TERM) и подождите несколько секунд.
2. Если не помогло, следующий на очереди сигнал 2 «SIGINT» (аналог ctrl+c)
3. Далее пробуем 1 «SIGHUP«, которая делает вид что мы закрыли терминал и больше не смотрим в программу.

Если ничего из вышеперечисленного не помогло — можно прибегнуть к kill -9 , но в дальнейшем избавьтесь от этой идиотской программы, которая не может нормально завершить свою работу.

Метки: , , , ,
Опубликовано в Без рубрики

Язык Go. Массивы, части (и строки): Механика ‘append’ ч.1

Предисловие

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

  • Размер фиксированный или изменяемый?
  • Влияет ли размер на тип массива?
  • Как выглядят многомерные массивы?
  • Есть ли смысл в выражении «пустой массив»?

Ответы на эти вопросы определят — являются ли массивы просто некоторым дополнением, либо это ключевой элемент языка.

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

В этой записи мы попробуем прояснить недоразумение, для чего по частям разберем принцип работы встроенной функции ‘append’ — как и почему она работает.

Массивы

Массивы — важный строительный блок в Go, но как фундамент здания они часто скрыты за более видимыми компонентами. Мы немного поговорим на эту тему, прежде чем двинуться дальше, к более интересной идее частей (slices).

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

Такое объявление массива

var buffer [256]byte

указывает некий буфер переменных размером 256 байт. Тип буфера включает его размер — 256. Массив из 512 байт будет отдельным уникальным типом — [512]byte.

Семантически это выглядит так:

buffer: byte byte byte  ... 256 раз ... byte byte byte

Это все. Переменная храни 256 байт данных и больше ничего. Мы можем работать с этими элементами привычными индексами, buffer[0], buffer[1] и так далее до buffer[255] (диапазон покрывает 256 элементов). Попытка произвести какие-либо действия со значениями вне этих рамок приведут к краху программы.

Существует встроенная функция len, которая возвращает число элементов массива, части и еще некоторых типов данных. Для массивов — очевидно что вернет len. В нашем случае len(buffer) ответит фиксированным числом — 256.

Массивы — хорошая вещь для работы с матрицами, но их наиболее частое использование в Go, это хранение частей.

Возьмем нашу переменную из прошлого примера и сделаем из него часть, содержащую в себе элементы с 100 по 150-ый (если быть точнее , от 100 до 149 включительно) отрезав часть от buffer:

var slice []byte = buffer[100:150]

Так выглядит полная форма объявления переменной. Тип переменной []byte читается как «часть массива байтов» (slice of bytes) и инициализируется из массива. Более идиоматичный синтаксис выглядит так:

var slice = buffer[100:150] 

без явного объявления типа. Внутри функции мы можем использовать краткую форму:

slice := buffer[100:150]

Так что же такое — часть переменной? Упрощенно, представьте себе часть переменной как структуру из двух элементов: длина и указатель массива. Можно представить себе ее выглядящей так:


type sliceHeader struct {
     Length         int
     ZerothElement  *byte
}

slice := sliceHeader { 
     Length:        50,
     ZerothElement: &buffer[100],
}

Но конечно это не совсем так, хоть и дает правильное представление о механике.

Итак мы сделали часть (slice) из массива, но также мы можем делать следующее:

slice2 := slice[5:10]

Как и ожидаемо, эта операция создает новую часть, в нашем случае — часть из элементов с 5 по 9 включительно, оригинальной части переменной, т.е. 105—109 элементы начального массива. Воображаемая структура sliceHeader для slice2 будет выглядеть так:

slice2 := sliceHeader{
      Length:        5,
      ZerothElement: &buffer[105],

}

Обратите внимание, указатель все еще установлен на оригинальный массив, содержащийся в переменной buffer.

Также можно «переразрезать» часть, и сохранить результат поверх оригинальной части:

slice = slice[5:10]

воображаемая структура sliceHeader будет выглядеть также, как для slice2. Пример ниже отбрасывает первый и последний элементы нашей части:

slice = slice[1:len(slice)-1]

От опытных программистов Go вы можете часть слышать «заголовок части переменной» (slice header), поскольку именно это и хранится в переменной. К примеру, если мы вызываем функцию, которая принимает в качестве аргумента часть переменной, например bytes.IndexRune, заголовок — это то, что будет передано в функцию

slashPos := bytes.IndexRune(slice, '/')

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

Передаем части параметром в функции

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

Это важно.

Когда мы вызываем IndexRune из предыдущего примера, мы передаем копию(!) заголовка части. Это поведение имеет важное последствие.

Рассмотрим функцию:

func AddOneToEachElemen(slice []byte) {
    for i := range slice {
          slice[i]++
    }
}

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

Попробуйте это:

func main() {
    slice := buffer[10:20]
    for i := 0; i < len(slice); i++ {
        slice[i] = byte(i)
    }
    fmt.Println("before", slice)
    AddOneToEachElement(slice)
    fmt.Println("after", slice)
}

Вывод программы такой:
before [0 1 2 3 4 5 6 7 8 9]
after [1 2 3 4 5 6 7 8 9 10]

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

То что аргументом функции является копия видно из этого примера:

func SubtractOneFromLength(slice []byte) []byte {
    slice = slice[0 : len(slice)-1]
    return slice
}

func main() {
    fmt.Println("Before: len(slice) =", len(slice))
    newSlice := SubtractOneFromLength(slice)
    fmt.Println("After:  len(slice) =", len(slice))
    fmt.Println("After:  len(newSlice) =", len(newSlice))
}

Вывод программы такой:
Before: len(slice) = 50
After: len(slice) = 50
After: len(newSlice) = 49

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

Указатели на части: Приемники методов

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

func PtrSubtractOneFromLength(slicePtr *[]byte) {
    slice := *slicePtr
    *slicePtr = slice[0 : len(slice)-1]
}

func main() {
    fmt.Println("Before: len(slice) =", len(slice))
    PtrSubtractOneFromLength(&slice)
    fmt.Println("After:  len(slice) =", len(slice))
}

Before: len(slice) = 50
After: len(slice) = 49

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

Допустим нам нужен метод для части, отрезающий последний слэш. Можем записать так:

type path []byte

func (p *path) TruncateAtFinalSlash() {
    i := bytes.LastIndex(*p, []byte("/"))
    if i >= 0 {
        *p = (*p)[0:i]
    }
}

func main() {
    pathName := path("/usr/bin/tso") // Conversion from string to path.
    pathName.TruncateAtFinalSlash()
    fmt.Printf("%s\n", pathName)
}

Вывод программы:
/usr/bin

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

type path []byte

func (p path) ToUpper() {
    for i, b := range p {
        if 'a' <= b && b <= 'z' {
            p[i] = b + 'A' - 'a'
        }
    }
}

func main() {
    pathName := path("/usr/bin/tso")
    pathName.ToUpper()
    fmt.Printf("%s\n", pathName)
}

Вывод программы:
/USR/BIN/TSO

Этот метод использует две переменные в конструкции for .. range чтоб получить индекс и элемент части. Эта форма цикла позволяет обойтись без множественного использования p[i] в теле.

Вместительность

Посмотрите на такую функцию, которая просто расширяет переданную ей аргументом часть одним элементом:

func Extend(slice []int, element int) []int {
    n := len(slice)
    slice = slice[0 : n+1]
    slice[n] = element
    return slice
}
func main() {
    var iBuffer [10]int
    slice := iBuffer[0:0]
    for i := 0; i < 20; i++ {
        slice = Extend(slice, i)
        fmt.Println(slice)
    }
}

Вывод программы:


[0]
[0 1]
[0 1 2]
[0 1 2 3]
[0 1 2 3 4]
[0 1 2 3 4 5]
[0 1 2 3 4 5 6]
[0 1 2 3 4 5 6 7]
[0 1 2 3 4 5 6 7 8]
[0 1 2 3 4 5 6 7 8 9]
panic: runtime error: slice bounds out of range

Все хроошо, часть растет до тех пор пока не поломается. Самое время поговорить о третьем компоненте заголовка части: вместительности:

type sliceHeader struct {

   Length        int
   Capacity      int
   ZerothElement *byte

}

Поле Capacity хранит в себе информацию о том, сколько на самом деле есть места в родительском массиве. Это максимальное значение которое может достичь Lenght. Попытка увеличить часть переменной за эти пределы приведет к панике.

Для определения вместительности части существует встроенная функция - cap:

if cap(slice) == len(slice) {
    fmt.Println("slice is full!")
}
Метки: , , ,
Опубликовано в Go

Как выбрать размер лог файла InnoDB (innodb_log_file_size)

Ответ на этот вопрос достаточно прост: Лог файл должен быть достаточно большим чтоб InnoDB мог оптимизировать свои I/O операции, но при этом не настолько большим, что восстановление после ошибки займет уйму времени.

Как же определить это значение? Есть достаточно простое правило.

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

Запустите следующие запросы во время пиковых нагрузок на сервер:

Отберем интересующие строчки:

mysql> pager grep sequence
PAGER set to 'grep sequence'

Возьмем значения переменной два раза, с минутным ожиданием:

mysql> show engine innodb status; select sleep(60); show engine innodb status;
Log sequence number 0 1605786842
1 row in set (0.00 sec)

1 row in set (1 min 0.09 sec)

Log sequence number 0 1606813289
1 row in set (0.00 sec)

Это значение ничто иное как количество байт записанных в лог транзакций. Итак, теперь мы знаем сколько мегабайт мы пишем в него в минуту. (Эта техника подходит для любых версий MySQL, в современных, 5.0 и выше, можно просто смотреть за переменной innodb_os_log_written из выдачи SHOW GLOBAL STATUS)

Возьмем калькулятор:
(1606813289 — 1605786842) /1024 /1024 = 0,98Мб в минуту.

Грубо говоря нам нужно сделать лог файл размера, способного вместить в себя максимум(!) час работы. Это обычно достаточно много данных InnoDB, и сбрасывать логи раз в час вполне разумно.

Итак, для нашего сервера получается следует выбрать 59Мб. Округлим до 64 для «красоты», и поскольку по умолчанию лог делится на два файла, делим пополам — получается:

innodb_log_file_size=32M

Выглядит удивительно мало? Может быть. Нам часто приходится сталкиваться с лог файлами размером в гигабайты, но чаще всего это просто ошибка. Например этот сервер, который мы использовали для примера достаточно неплохо нагружен (ø в час: 409,997 запросов, 6,1Гб трафик).
Конечно ни в коем случае нельзя оставлять размер по умолчанию (5Мб) на любом нагруженном сервере, но также не следует без меры увеличивать этот параметр.

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

Но повторяем: в большинстве случаев когда нам приходится производить тонкую настройку серверов — значение этой переменной приходится сильно снижать.
Глупый совет «вычислять размер файла исходя из размера буфера» советуем игнорировать.

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

Метки: , ,
Опубликовано в MySQL

Настройка MySQL: используем TMPFS как временный каталог

В своей работе мы неоднократно сталкивались с системами, на которых счетчик Created_tmp_disk_tables зашкаливал.
В документации MySQL достаточно ясно написано как он использует память и почему создает временные таблицы. Здесь же я хочу рассказать не про то «почему» MySQL это делает,
но — как увеличить производительность MySQL в случае создания временных таблицы на диске (будь то вина пользователей, или архитектуры MySQL).

Одним из вариантов является TMPFS. Ниже приведу один из вариантов, как это можно сделать:

Перед тем как начать убедитесь что у вас достаточно оперативной памяти для TMPFS. Обычно достаточно выделить 2Гб, но если ваша БД работает с большими объемами данных кучей неэффективных запросов, тогда вам мало что поможет.

Простой и достаточно безопасный способ создать TMPFS для MySQL:

Создаем каталог
# mkdir /tmp/mysql_tmp

Изменяем владельца
# chown mysql:mysql /tmp/mysql_tmp

Запоминаем id и gid пользователя mysql в нашей системе (101 и 103 в моем случае)
# id mysql
uid=101(mysql) gid=103(mysql) groups=103(mysql) context=root:system_r:unconfined_t:SystemLow-SystemHigh

Дописываем строку в fstab, чтоб после перезагрузки все работало (не забудьте изменить uid и gid)
# vi /etc/fstab
tmpfs /tmp/mysql_tmp tmpfs rw,uid=101,gid=103,size=2G,nr_inodes=10k,mode=0700 0 0

Пробуем монтировать нашу файловую систему
# mount /tmp/mysqltmp

Если все в порядке, дописываем в конфигурационный файл MySQL my.cnf, в секцию [mysqld] строку:
# vi /etc/my.cnf
tmpdir=/tmp/mysql_tmp/

После чего перезапускаем MySQL.
# service mysql restart

Вы сразу заметите насколько быстрее стал работать ваш сервер!

Метки: , , ,
Опубликовано в MySQL

Ошибка при запуске приложений 0х0000005 после обновления Windows 7

Вечером 14-го Августа 2013 года Компания Microsoft выпустила очередное обновление безопасности под номером 2859537. Многие компьютеры, получившее это обновление, восприняли его как что-то полезное, однако на самом деле данное обновление содержит ошибки. После перезагрузки компьютер отказывается запускать приложения показывая всего лишь одно и то же окно с надписью «Ошибка при запуске приложений 0xc0000005″.

Проблема является массовой, но решение найдено нами почти сразу. Есть два пути решения:

  1. Удалить некорректное обновление Windows 7 KB2859537.
  2. Запустить восстановление системы и «откатить» на 1-2 дня назад.

Более подробно:

Путь №1

  1. Запустить командную строку от имени Администратора (клавиша Windows + R).
  2. Выполнить команду: wusa.exe /uninstall /kb:2859537
  3. Перезагрузить компьютер.

Путь №2

  1. Пуск => Стандартные => Служебные => Восстановление системы.
  2. Выбрать точку восстановления за 13-14 Августа (или ранее).
  3. Перезагрузить компьютер.

 

Метки: ,
Опубликовано в Microsoft

AngularJS — хитрости и трюки ч.1

Наблюдение за объектов или листом

Если вы наблюдаете за листом или объектом не установив параметр objectEquality , то обратный вызов $watch не сработает, если объект изменен только частично. Установив в true параметр вызов будет срабатывать в случае любых модификаций, что скажется на производительности. Использовать с осторожностью!

Двусторонняя связь атрибута без явного объявления области видимости

Иногда возникает необходимость получить доступ к атрибуту директивы для двусторонней связи не объявляя этого явно в конфигурации области видимости директивы. Это можно осуществить с использованием сервиса $parse.

Если область видимости вашей директивы изолирована ( scope: {} ), следует использовать scope.$parent вместо scope:

var app = angular.module('demo', []);
app.controller('DemoCtrl', function($scope) {
    $scope.reset = function() {
        $scope.data = {
           email: [email protected]'
        };
    };
    $scope.reset();
});
app.directive('myDirective', ['$parse', function($parse) {
    return {
        restrict: 'A',
        scope: true,
        link: function(scope, iElement, iAttrs) {
            var attrModel = $parse(iAttrs.myDirective)
            function updateContents() {
                // Получаем значение атрибута и обновляем содержимое директивы
                iElement.html('directive: ' + attrModel(scope));
            }
            scope.$watch(attrModel, function(newValue) {
                // следим за атрибутами модели
                updateContents();
            });
            scope.changeValue = function(newValue) {
                // присваиваем значение атрибуту модели
                attrModel.assign(scope, newValue);
                updateContents();
            }
            updateContents();
        }
    }
}]);
Метки: ,
Опубликовано в JavaScript