Если нельзя, но очень хочется, то нужно обязательно и ничего в мире не стоит того, чтобы делать из этого проблему!


Интересна Java? Кликай по ссылке и регистрируйся!
Если тебе полезно что-то из того, чем я делюсь в своем блоге - можешь поделиться своими деньгами со мной.
с пожеланием
столько времени читатели провели на блоге - 
сейчас онлайн - 

среда, 17 июля 2013 г.

"Всё, что вы видите во мне - это не моё, это ваше. Моё - это то, что я вижу в вас..."


И это гениально. Я эту картинку нашел на просторах фейсбука, в группе "Фитнес для мозга". Там много жизнеутверждающего есть, но эта картинка.... 

Я давненько наблюдал за тем, что вокруг вообще нет никого. Как оказалось, мой мозг так устроен, что он не может воспринимать что-то другое не через призму опыта. Я думаю что речь сейчас идет про левое полушарие, которое любит вешать на все ярлыки... Так вот вокруг я вижу не Васю, Петю, Олю и Катю, а Санька, Санька, Санька и Санька.... Разные люди показывают меня разного - того меня, каким бы я мог бы быть в каком-то пространстве-времени (при каких-то условиях). И если человек мне не нравится, значит я не нравлюсь себе таким. Если человек мне нравится - значит я такой себе нравлюсь, я таким собой горжусь, уже есть или хочу стать... 

Если с друзьями все понятно - с ними приятно, они мне напоминают себя и это мне нравится, то что делать с теми людьми (таким собой), который не мне сейчас нравится? Обычно, и это кажется логичным - я стремлюсь переучить того, кто рядом. Причем мастерски пытаюсь сломать его оборону. А если ничего не получается, Я просто отстраняюсь и больше с ним не общаюсь. Это классика жанра. Кто так не делал? 

Но если держать в голове тот факт, что я вижу не Его рядом с собой а Себя, который мне не нравится, то тут есть над чем поработать. Кроме того, почему-то именно этот человек повстречался на моем пути. Он зацепил меня, не Васю, Петю, Олю, а меня... И не важно это злой гопник в подворотне, или злая тётенька в ЖЭК'е. Он появился именно на моем пути. И я уже более чем уверен, что притянул я его не даром - он мой тренер. Он пришел ко мне, чтобы показать мне меня такого, каким я не люблю еще себя. Он пришел для того, чтобы я мог интегрировать в себе еще одну часть себя. И поверь, он уйдет как только я это сделаю. 


Это самая яркая картинка, которую удалось найти (Спасибо, http://demotivation.me/). И она не утрирована. Человек действием своим притягивает в свою жизнь разного рода тренеров. И как только очередной этап тренинга закончится - вдруг замечаешь, что тебя больше не парит все то, что парило раньше и вдруг для тебя перестает существовать целая категория людей, которые раньше тебе проходу не давали... 

Однажды к мастеру восточной борьбы пришёл один человек и спросил: «Учитель, я чемпион своей страны по боксу и борьбе, можешь ли ты научить меня чему-нибудь новому?». Учитель организовал дружественный спарринг своих учеников с заморским бойцом. Боец принял бой и всех разгромил. После чего подошел к учителю и сказал: «Я только что разгромил всех твоих учеников, ты все еще уверен, что можешь меня научить чему-то новому?». Старый мастер ответил: «Представь такую ситуацию: ты зашёл в тёмный переулок, а там тебя поджидают три здоровых громилы, они значительно больше тебя, сильнее, да к тому же вооружены и мечтают избить и ограбить тебя. Ты ведь легко справишься с ними, так?». «Безусловно» - ответил боец. Старец продолжил: «Так вот я научу тебя ходить по таким переулкам, на которых громил не будет…».

И тут "перестанут существовать" стоит понимать не буквально - они будут там же, на тех же местах, делать то же, что и раньше делали, но ты будешь видеть их другими. А раз так, то и делать они в этом контексте твоего видения будут совсем другое... Можно даже придумать метафору. Чем более разного ты себя любишь, тем с большей частотой колеблются твои мысли - а раз так, то из всего спектра излучений, которое излучает Действительность ты видишь в заданном узком спектре частот. Для наиболее неподготовленных - радиоволны, дальше инфракрасное изучение, потом видимый диапазон, потом ультрафиолетовое, потом рентгеновское и гамма излучение.  Глядя на один и тот же мир в разных спектрах ты видишь его разным. Хотя, если развивать эту метафору, то быть может ты видишь все в большем диапазоне, постепенно охватывая все больше информации и видя картину более полной и цветной... Надо подумать.... 

Собираем все воедино. Я вижу вокруг только части себя. Я могу их интегрировать, а могу и дальше отвергать. Интегрировать их я могу методом "полюби ближнего своего, как самого себя", то есть "полюби себя такого", то есть "полюби эту свою часть которую ты сейчас видишь, ведь видишь в других ты только себя". И размышляя над этим всем в процессе обсуждения с другом мы вдруг нащупали новую метафору. Вокруг никого нет - а я шизофреник. Ну я говорю сейчас про ту шизофрению, которую можно наблюдать в фильме "Игры Разума". Если все, что я вижу в других людях - это мое, то нет никаких других. Есть каждый сам по себе в центре сферы своей шизофрении. В таком себе коконе что-ли. Он видит спектакль из частей, которые рождает его мозг. Пока он не интегрируется с этими частями, он не увидит того, что в действительности происходит. 

Как я могу знать, что ты чувствуешь? Как ты можешь знать, что чувствую я? И пусть я даже напишу 100500 слов описывающего то, что происходит внутри - никто и никогда не поймет этого, потому как в тексте моем увидит себя. Потому для тебя нет никакого меня. Есть только ты и твой внутренний мир, модель, карта, реальность. А в действительности оно хз какое. 


Однажды четверо слепых захотели узнать, что же такое слон, на что он похож хотя бы. Попросили подвести их к слону. Один потрогал слона за хобот, и подметил: "Слон на толстый канат похож". Второй потрогал хвост, и возразил ему: «Нет, ну не на канат, а на верёвку скорее...».   Третий, который трогал слона за ногу, возразил: «Нет, он на столб похож вообще-то». А четвёртый, который трогал за брюхо, сказал: «Вы не правы все трое! Слон похож на бочку огромную!».  И слепцы оживлённо заспорили по поводу того, на что же похож слон всё-таки на самом деле. И все они были не правы, и каждый из них прав был по-своему…  http://csps.edusite.ru/p38aa1.html

Четырехмерное. Вот! Вот какое Оно все вокруг. Может даже и намного более мерное... Хочется тут выложить этот видеоролик про красивые 4х-мерные объекты этого мира, которы мы видеть не умеем и не научены. 


Вот как-то так и Действительность - она где-то есть, но мы как те двухмерные ящерицы....

Прием.

Играем на фортепиано на Java: Шаг 3 - Играем аккорды

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

Для удобства ввел понятие нота, она инкапсулирует в себе то число, которое я назвал тональностью - оно является кодом ноты на midi устройстве.
public class Нота {
    private int тональность;

    public Нота(int тональность) {
        this.тональность = тональность;
    }

    public Нота(Нота нота) {
        тональность = нота.тональность();
    }

    public int тональность() {
        return тональность;
    }
}
Я избавился от нот в Тональностях, потому что нелогично - ее можно сыграть от какой-то ноты, но держать для каждой из нот копию Можор, Минор и так далее - не ок...
public enum Тональность {

    Мажор(Тон, Тон, Полутон, Тон, Тон, Тон, Полутон),
    Минор(Тон, Полутон, Тон, Тон, Полутон, Тон, Тон),
    МинорГармонический(Тон, Полутон, Тон, Тон, Полутон, МалаяТерция, Полутон),
    МинорМелодический(Тон, Полутон, Тон, Тон, Тон, Тон, Полутон);

    private Интервал[] интервалы;

    private Тональность(Интервал... интервалы) {
        this.интервалы = интервалы;
    }

    public Нота get(Нота from, int order) {
        int sum = 0;
        for (int index = 0; index < order - 1; index++) {
            sum += 2*интервалы[index].интервал();
        }
        return new Нота(from.тональность() + sum);
    }
}
По аналогии я создал понятие Трезвучие
public enum Трезвучие {

    Мажорное(БольшаяТерция, МалаяТерция),
    Минорное(МалаяТерция, БольшаяТерция),
    Уменьшенное(МалаяТерция, МалаяТерция),
    Увеличенное(БольшаяТерция, БольшаяТерция);

    private Интервал[] интервалы;

    private Трезвучие(Интервал... интервалы) {
        this.интервалы = интервалы;
    }

    public List<Нота> get(Нота from) {
        List<Нота> result = new LinkedList<Нота>();

        int sum = 0;
        result.add(new Нота(from));

        for (Интервал i : интервалы) {
            sum += 2*i.интервал();

            result.add(new Нота(from.тональность() + sum));
        }

        return result;
    }
}
Оно очень похоже, только его основной метод расчета дает сразу три ноты, которые потом синтезатор отыграет. Добавил понятие октав
public abstract class Октава {

    private List<Нота> ноты = new LinkedList<Нота>();
    private Октава следующая;
    private Октава предыдущая;

    public void init(Октава предыдущая, Октава следующая, int... ноты) {
        this.следующая = следующая;
        this.предыдущая = предыдущая;
        for (int нота : ноты) {
            this.ноты.add(new Нота(нота));
        }
    }

    public abstract Нота база();

    public Нота get(char нота) {
        switch (нота) {
            case 'C' : return get(1);
            case 'D' : return get(2);
            case 'E' : return get(3);
            case 'F' : return get(4);
            case 'G' : return get(5);
            case 'A' : return get(6);
            case 'H' : return get(7);
            default: throw new IllegalArgumentException("Нет такой ноты");
        }
    }

    public Нота get(int номерНоты) {
        return ноты.get(номерНоты - 1);
    }

    public Октава следующая() {
        return следующая;
    }

    public Октава предыдущая() {
        return предыдущая;
    }
}
И для каждой октавы реализовал наследника
public class ПерваяОктава extends Октава {

    private static ПерваяОктава instance;
    public static ПерваяОктава get() {
        return (instance != null)?instance:new ПерваяОктава();
    }

    public static Нота C4 = ПерваяОктава.нота(1);
    public static Нота D4 = ПерваяОктава.нота(2);
    public static Нота E4 = ПерваяОктава.нота(3);
    public static Нота F4 = ПерваяОктава.нота(4);
    public static Нота G4 = ПерваяОктава.нота(5);
    public static Нота A4 = ПерваяОктава.нота(6);
    public static Нота H4 = ПерваяОктава.нота(7);

    private static Нота нота(int номерНоты) {
        return get().get(номерНоты);
    }

    public ПерваяОктава() {
        instance = this;
        init(МалаяОктава.get(), ВтораяОктава.get(), 48, 50, 52, 53, 55, 57, 59);
    }

    @Override
    public Нота база() {
        return get(1);
    }
}
Избыточно немного, но пусть будет. Не пригодится потом удалю... А так я изменил синтезтор
public class Синтезатор {

    private MidiChannel midi;

    public Синтезатор(MidiChannelFactory midiFactory) {
        this.midi = midiFactory.get();
    }

    public void звучать(Нота нота, int длительность, int сила) {
        midi.noteOn(нота.тональность(), сила);
        пауза(длительность);
        midi.noteOff(нота.тональность());
        пауза(длительность);
    }

    public void звучать(Нота нота, int сила) {
        midi.noteOn(нота.тональность(), сила);
    }

    public void звучать(Нота отНоты, Тональность тональность, int длительность, int сила) {
        for (int index = 1; index <= 8; index++) {
            звучать(тональность.get(отНоты, index), длительность, сила);
        }
    }

    public void звучать(Нота отНоты, Трезвучие трезвучие, int сила) {
        List<Нота> аккорд = трезвучие.get(отНоты);
        for (Нота нота : аккорд) {
            звучать(нота, сила);
        }
    }

    private void пауза(int длительность)  {
        try {
            Thread.sleep(длительность);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
Появился интерфейс
public interface MidiChannelFactory {
    MidiChannel get();
}
А метод создания конкретного звучащего устройства ушло в новый класс
import javax.sound.midi.*;

public class RealMidiChannelFactory implements MidiChannelFactory {

    @Override
    public MidiChannel get() {
        try {
            // init sequencer
            Sequencer sequencer = null;
            sequencer = MidiSystem.getSequencer();
            sequencer.open();

            // init synthesizer
            Synthesizer synth = MidiSystem.getSynthesizer();
            synth.open();

            // get channel for synthesizing: the highest numbered channel.  sets it up
            MidiChannel[] channels = synth.getChannels();
            MidiChannel midi = channels[channels.length - 1];
            midi.programChange(0);

            midi.noteOn(0, 10);
            sleep();
            midi.noteOff(0);
            return midi;
        } catch (MidiUnavailableException e) {
            throw new RuntimeException(e);
        }
    }

    private void sleep() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Зато теперь синтезатор можно протестировать
import com.apofig.октавы.ПерваяОктава;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import javax.sound.midi.MidiChannel;

import java.util.Arrays;
import java.util.LinkedList;

import static junit.framework.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.*;

public class СинтезаторTest {

    private MidiChannel midi;
    private Синтезатор синтезатор;

    @Before
    public void setup() {
        RealMidiChannelFactory factory = mock(RealMidiChannelFactory.class);
        midi = mock(MidiChannel.class);
        when(factory.get()).thenReturn(midi);

        синтезатор = new Синтезатор(factory);
    }

    @Test
    public void shouldPlayДоМажорСПервойОктавы() {
        синтезатор.звучать(ПерваяОктава.get().get('C'), Тональность.Мажор, 1, 120);

        assertPlay(48, 50, 52, 53, 55, 57, 59, 60);
    }

    private void assertPlay(Integer... expected) {
        ArgumentCaptor captor = ArgumentCaptor.forClass(Integer.class);
        verify(midi, times(expected.length)).noteOn(captor.capture(), anyInt());

        LinkedList expected1 = new LinkedList();
        expected1.addAll(Arrays.asList(expected));
        assertEquals(expected1.toString(), captor.getAllValues().toString());
    }

    @Test
    public void shouldPlayЛяМажорСПервойОктавы() {
        синтезатор.звучать(ПерваяОктава.get().get('A'), Тональность.Мажор, 1, 120);

        assertPlay(57, 59, 61, 62, 64, 66, 68, 69);
    }

    @Test
         public void shouldPlayЛяМинорСПервойОктавы() {
        синтезатор.звучать(ПерваяОктава.get().get('A'), Тональность.Минор, 1, 120);

        assertPlay(57, 59, 60, 62, 64, 65, 67, 69);
    }

    @Test
    public void shouldPlayМажорныйАккордСПервойОктавы() {
        синтезатор.звучать(ПерваяОктава.get().get('C'), Трезвучие.Мажорное, 120);

        assertPlay(48, 55, 52);
    }

    @Test
    public void shouldPlayМинорныйАккордCПервойОктавы() {
        синтезатор.звучать(ПерваяОктава.get().get('C'), Трезвучие.Минорное, 120);

        assertPlay(48, 51, 55);
    }
}
Вот как бы и все пока. Теперь можно изучать, как звучат разные аккорды, что мне было и нужно....
import com.apofig.октавы.ПерваяОктава;
import static com.apofig.Трезвучие.Мажорное;

public class Main {

    public static void main(String[] args) {
        Синтезатор синтезатор = new Синтезатор(new RealMidiChannelFactory());

//        синтезатор.звучать(ПерваяОктава.get().get('C'), Мажорное, 120);
        синтезатор.звучать(ПерваяОктава.get().get('C'), Мажорное, 120);
    }
}
Продолжение следует... А пока вот исходники к этим трем частям (с git репозиторием).

вторник, 16 июля 2013 г.

Играем на фортепиано на Java: Шаг 2 - Играем гаммы в разных тональностях

В прошлый раз мы научились извлекать ноту До из джавы. А теперь хочется поиграть по всем белым нотам в тональности До мажор. При этом хочется, чтобы в коде отражалась информация впитанная мной из сети на тему гармонии... Кодить я буду на русском и немного отходя от java code conventions, потому будет немного странно... Но это только в начале - цель моя максимально передать Музкальный DSL в коде...

Для начала разберемся с интервалами
public enum Интервал {

    ЧистаяПрима(0),
    МалаяСекунда(0.5), Полутон(0.5),
    БольшаяСекунда(1), Тон(1),
    МалаяТерция(1.5),
    БольшаяТерция(2),
    ЧистаяКварта(2.5),
    УвеличеннаяКварта(3), УменьшеннаяКвинта(3),
    ЧистаяКвинта(3.5),
    МалаяСекста(4),
    БольшаяСекста(4.5),
    МалаяСептима(5),
    БольшаяСептима(5.5),
    ЧистаяОктава(6);

    private double интервал;

    private Интервал(double интервал) {
        this.интервал = интервал;
    }

    public double интервал() {
        return интервал;
    }
}
Теперь нам понадобятся тональности. Закодим для начала две самые белые мажорные (До и Ля) и пару разновидностей Ля Минора.
public enum Тональность {

    ДоМажор(60, Тон, Тон, Полутон, Тон, Тон, Тон, Полутон),
    ЛяМажор(57, Тон, Тон, Полутон, Тон, Тон, Тон, Полутон),
    ЛяМинор(57, Тон, Полутон, Тон, Тон, Полутон, Тон, Тон),
    ЛяМинорГармонический(57, Тон, Полутон, Тон, Тон, Полутон, МалаяТерция, Полутон),
    ЛяМинорМелодический(57, Тон, Полутон, Тон, Тон, Тон, Тон, Полутон);

    private int базоваяНота;
    private Интервал[] интервалы;

    private Тональность(int базоваяНота, Интервал... интервалы) {
        this.базоваяНота = базоваяНота;
        this.интервалы = интервалы;
    }

    public int get(int порядок) {
        int интервал = 0;
        for (int index = 0; index < порядок - 1; index++) {
            интервал += интервалы[index].интервал()*2;
        }
        return базоваяНота + интервал;
    }
}
А теперь поиграем гаммы в разных тональностях. Для этого я выделил в новый класс синтезатор из Main.
package com.apofig;

import javax.sound.midi.*;

public class Синтезатор {

    private MidiChannel synthChannel;

    public Синтезатор() {
        try {
            // init sequencer
            Sequencer sequencer = null;
            sequencer = MidiSystem.getSequencer();
            sequencer.open();

            // init synthesizer
            Synthesizer synth = MidiSystem.getSynthesizer();
            synth.open();

            // get channel for synthesizing: the highest numbered channel.  sets it up
            MidiChannel[] channels = synth.getChannels();
            synthChannel = channels[channels.length - 1];
            synthChannel.programChange(0);
            звучать(Тональность.ДоМажор.get(1), 10, 1);
        } catch (MidiUnavailableException e) {
            throw new RuntimeException(e);
        }
    }

    public void звучать(int нота, int длительность, int сила) {
        synthChannel.noteOn(нота, сила);
        пауза(длительность);
        synthChannel.noteOff(нота);
        пауза(длительность);
    }

    public void звучатьГамму(Тональность тональность, int длительность, int сила) {
        for (int index = 1; index <= 8; index++) {
            звучать(тональность.get(index), длительность, сила);
        }
    }

    private void пауза(int длительность)  {
        try {
            Thread.sleep(длительность);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
А в Main осталось совсем немного
public class Main {

    public static void main(String[] args) {
        Синтезатор синтезатор = new Синтезатор();

        final int delay = 300;
        int сила = 120;

        синтезатор.звучатьГамму(ДоМажор, delay, сила);
        синтезатор.звучатьГамму(ЛяМажор, delay, сила);
        синтезатор.звучатьГамму(ЛяМинор, delay, сила);
        синтезатор.звучатьГамму(ЛяМинорГармонический, delay, сила);
        синтезатор.звучатьГамму(ЛяМинорМелодический, delay, сила);
    }
}
На этом пока все... Продолжение тут...

Играем на фортепиано на Java: Шаг 1 - Извлекаем ноту до.

Моя задача разобраться в гармонии, аккордах, размерностях, интервалах, тональностях и прочих прелестях музыки как точной науки. Вдохновившись тем, как ребята пишут музыку на своем Overtone

Quick Intro to Live Programming with Overtone from Sam Aaron on Vimeo.

а так же вооружившись своей ленью изучать новый язык программирования (ребята пишут на clojure), я стал ковырять решения на Java. И уже через пол часа я извлек из пакета javax.sound.midi.* ноту до. Делается это так.
package com.apofig;

import javax.sound.midi.*;

public class Main {

    public static final int Do = 60;

    public static void main(String[] args) throws MidiUnavailableException, InterruptedException {
        // init sequencer
        Sequencer sequencer = MidiSystem.getSequencer();
        sequencer.open();

        // init synthesizer
        Synthesizer synth = MidiSystem.getSynthesizer();
        synth.open();

        // get channel for synthesizing: the highest numbered channel.  sets it up
        MidiChannel[] channels = synth.getChannels();
        MidiChannel synthChannel = channels[channels.length - 1];
        synthChannel.programChange(0);

        synthChannel.noteOn(Do, 120);

        Thread.sleep(100);

        synthChannel.noteOff(Do);
    }
}
Все крайне просто... Спасибо проекту Virtual-Piano за быстрый старт.

Продолжение тут...

Мой персональный джин

Белла

...вчера все утро в голове играла мелодия. Причем даже не мелодия, а так припевчик... Решил наиграть его на синтезаторе. Потом записать в MIDI на компе. Так пару часиков и готово то, что готово. Ближе к концу поня,л что это было - заканчивал с мыслью про этот несчастный случай, о котором мне стало известно в то же утро. У Мамы в Черновцах сотрудница умерла - молодая девушка Белла. Они работали вместе с Мамой в кафе. Там я частенько видел Беллу. Она всегда улыбалась. А теперь ее нет.

Пусть эта мелодия будет для нее, где бы она не была сейчас...

понедельник, 15 июля 2013 г.

пятница, 12 июля 2013 г.

Во как!


Он никого не играл,
Он пытался лишь быть собой.
Он был почти одинок.
Потому что он был другой.

В жизни наверное нет
Двух одинаковых дней.
Двух одинаковых нет
И на земле людей.

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

В жизни наверное нет
Двух одинаковых дней.
Но каждый день поутру
Он уходил за ней.

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

Он ничего не менял
И не вел никого на бой.
Он за собою не звал.
Он пытался лишь быть собой.

В жизни наверное нет
Двух одинаковых дней.
Двух одинаковых нет
И на земле людей.

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

четверг, 11 июля 2013 г.

JavaScript гид по сайту

Люблю джаваскрипт за то, что c ним порой чувствуешь себя магом и волшебником. Не так давно в голове возникла идея - а что, если на сайт, который изначально не гибок в этом плане (без аджакса и джаваскриптовой цветомузыки) навешать немного джаваскрипта. Скажу сразу, речь идет об LMS Moodle (для тех, кто не в курсе - это CMS для тренингов). Так вот была у нас одна проблемка с ним - много че может делать, только вот ничего не понятно как это сделать - часто пользователи нас спрашивают "а как то?", "а как это?", причем, порой, даже сам забываешь где там кликнуть надо... Люблю я его за это - квестообразующий :) - не соскучишься с ним. Но это мне так интересно, а другим пользователям? Нужно максимально упрощать!

Идея пришла во время серфинга на другом сайте. Там был простенький гид, кликни там, кликни сям, а тут вот это, а тут ты можешь сделать это. И я подумал - хочу! Стал искать решения. Их есть с десяток. Но я хотел решения, которое будет чисто джаваскриптовым - без правки HTML. И оно нашлось! Сразу показываю результат, каким он получился у меня.


Есть такая библиотека с использованием JQuery, называется Guiders-JS. Настраивается достаточно не сложно. Вот код, который я вставил в боковую панельку чтобы линк Training Guide ожил.

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
    <li>...</li>
    <li><span id="training-guide"><a href="#">Training guide</a></span></li>
</ul>

<p id="training-guide-script">
    <script src="https://host.com/js/guiders-1.3.0/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="https://host.com/js/guiders-1.3.0/guiders-1.3.0.js" type="text/javascript"></script>
    <link rel="stylesheet" href="https://host.com/js/guiders-1.3.0/guiders-1.3.0.css" type="text/css" />
    <script src="https://host.com/js/guiders-1.3.0/training-guiders.js" type="text/javascript"></script>
</p>
Все просто. Создается линк никуда не ссылающийся (на него потом навешается обработчик с помощью jQuery). Подключается библиотека jQuery и Guiders-JS, подключается стиль и мой скрипт, в котором описаны окошки гида. Там же и навешивается обработчик на клик и делаются еще кой че.
$(document).ready(function () {
    if ($("#module-1224").size() == 0) {       // проверяем, если мы не на главной страничике (содержащей див
                                               // с айди module-1224), то запускать гид бессмысленно
        $('#training-guide').parent().hide();  // потому мы скрываем возможность вызвать гида
        return;
    }

    $('#training-guide').click(function () {  // при клике на линк  
        guiders.show("start");                       // открываем гид (первый диалог)
    });

    guiders.createGuider({      // создается первый диалог
        buttons: [              // с кнопкой next
            {name: "Next"}
        ],

        title: "**** ******* Guide", // это его заголовок
        description: "Hi! This is **** ****** training course guide. Hope it will help.", // с сообщением

        id: "start",           // это его айдиха
        next: "guide2",         // это айдиха того, куда переходим

        overlay: true,          // задний фон за диалогом будет затеняться
        xButton: true,          // у диалога будет кнопка X в правом верхнем углу
        closeOnEscape: false,   // по нажатию на Esc будет закрыто окно
        width: 350              // ширина диалога
    }).show();

    guiders.createGuider({      // создаем следующий шаг
        attachTo: "#inst16",    // он прикрепляется к диву с этой айдишкой
        position: 10,           // прицепляется в позиции 10. С каждой стороны к диву можно прицепиться: 
                                // с одного краю, с другого и по центру - всего 12 позиций. По часовой 
                                // стрелке от 1 до 12.
                                // 
                                // вот кусочек исходного кода библиотеки:
                                //    guiders._offsetNameMapping = {
                                //        "topLeft": 11,
                                //        "top": 12,
                                //        "topRight": 1,
                                //        "rightTop": 2,
                                //        "right": 3,
                                //        "rightBottom": 4,
                                //        "bottomRight": 5,
                                //        "bottom": 6,
                                //        "bottomLeft": 7,
                                //        "leftBottom": 8,
                                //        "left": 9,
                                //        "leftTop": 10
                                //     "};

        overlay: true,          // опять же фон будет размыт и в тени
        highlight: "#inst16",   // но сам див будет подсвечен

        buttons: [ {name: 'Next', onclick: guiders.next} ], //" на кнопку next навешивается обработчик - следующий диалог                      

        title: "",
        description: "You you can find useful links here.", // другое сообщение

        id: "guide2",          // айдиха текущего диалога
        next: "guide3",        // куда идем на следующий диалог

        autoFocus: true,       // если вдруг див ушел за пределы экрана, подсветить его проскролив страничку
        xButton: true,
        closeOnEscape: false,
        width: 350
    });

    function topic_toggle_new(number, isOpen) {  // это самописная функция которая разворачивает/сворачивает 
                                                 // модуля тренинга на Moodle, вызывая его js код
        var open = $("#toggle-" + number + " .toggle_closed");
        open = (open.size() > 0) ? open[0] : null;

        var close = $("#toggle-" + number + " .toggle_open");
        close = (close.size() > 0) ? close[0] : null;

        if (isOpen) {
            element = (open == null) ? null : open;
        } else {
            element = (close == null) ? null : close;
        }

        if (element != null) {
            toggle_topic(element, number);
        }
    }

    guiders.createGuider({         // создаем третий шаг
        attachTo: "#inst370",
        position: 10,

        highlight: "#inst370",
        overlay: true,

        buttons: [
            {name: "Next", onclick: function () {  // вот тут на next навешиваем больше чем одну 
                                                   // функцию - создли анонимную функцию и в ней 
                                                   // прописали весь сценарий  
                topic_toggle_new(1, false);
                topic_toggle_new(2, false);
                topic_toggle_new(3, false);
                topic_toggle_new(4, false);
                topic_toggle_new(5, false);
                topic_toggle_new(6, false);
                topic_toggle_new(7, false);
                topic_toggle_new(8, false);
                topic_toggle_new(9, false);
                topic_toggle_new(10, false);
                guiders.next();
            }}
        ],

        title: "",
        description: "For each code review you'll get 3 XP. More code " +
            "review you do - more XP you get. Collect XP and " +
            "distinguish yourself!",

        id: "guide3",
        next: "guide4",

        autoFocus: true,
        xButton: true,
        closeOnEscape: false,

        width: 350
    });

    // ну и так далее. На последнем шаге добавляется кнопка Close вот так
    // buttons: [{name: "Close", onclick: guiders.hideAll }]
    // ... 
});
Что замечательно, так это то, что я могу по линку https://host.com/training-page.html#guider=start открыть страничку с гидом.
Enjoy! И спасибо разработчикам Guiders-JS!!

Есть что предложить?

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


Работа из-дому. Или work from home. Кто-то называет это sleep from home. Ну да, при жесткой нехватке выходных дней в месяце лишний work from home превращается в sleep from home. И хорошо что так, иначе организм все-равно свое заберет - через больничный. А что если каждый день работать из-дому?


Раздражители. Это первое, на что я жаловался. В офисе (айтишном) не всегда, но чаще всего как в библиотеке. То есть тихо. Дома не так. Дома перфорасты-соседи с 10:00 начинают делать дыры в савковом бетоне. Дома иногда ребенок не в садике. Дома жена хочет послушать музыку или сварить кукурузу. Дома папа доступен для семейных задач: поиграться в куклы, забить гвоздь... И объяснить что такое состояние потока, ни 4х-годовалому ребенку, ни любимой жене  так и не получилось. Потому искал спокойное время суток.


Ночная смена. Где-то после 23 часов время как-то странно себя ведет. Состояние потока легче достичь. И не только потому, что все домашние уже спят. Спят и соседи-перфорасты. Спит (или готовится) большая часть Киева. Уровень суеты в воздухе падает и легче поймать поток. А там уже и утро скоро.... Но есть но.


Здоровье. Как ни крути но человек такое животное, для работы днем приспособлено. И все, что не попадает в отрезок от "первых петухов" до "что-то я устал, день был насыщенный - пора и байки" - все во вред. Если делать это не регулярно - можно и не заметить. Но если работать из-дому каждый день и ближе к ночи, тогда начинается режим "а не пойти ли нам на больничный, а?" Что делать?


Жаворонки. Совместно с совами делят людей на две группы. Но на самом деле все люди - жаворонки. Это я понял, когда пару месяцев подряд вставал в 5 утра, а ложился в 22. Это был самый творческий период в моей жизни. Как оказалось позже - мозг наиболее креативен и продуктивен ранним утром. где-то с 4 и до 9 утра. Именно этот отрезок времени совы пытаются догнать, но силы уже не те - целый день догоняли жеж. Так что можно перенести ночные угукания в раннее цвиринькание. И будет толк. Знаю. За время с 5 до 10 я делал всю работу за день, а остальной день был свободен для не срочных но важных тасков. Отакое. Но и тут есть ложка дегтя.


Личная жизнь. Этим словосочетанием я называю то, что происходит у обычного офисного планктонщика после 19:00 (особенно в пятницу). Встреча с друзьями. Пивко. Дискотеки. Посиделки... Этого всего нет у жаворонков. Если ты встаешь в 5 утра, то к 21-22 спать хотеться будет очень. Так что я спрыгнул с этого двухмесячного марафона в пользу ночного угукания с друзьями. И что теперь? От чего веслали, к тому и приплыли.


Гибкость. Выход приходилось искать в чем-то другом. Если уж я хочу работать из-дому (почему хочу - отвечу позже) надо импровизировать. Искать закономерности. И вилять, мимо них... Сосед не весь день перфоратором орудует. Жена отводит ребенка в садик а сама идет на базар. После обеда даже пробовать работать не стоит - голова не варит. Ко сну ребенок отходит в 22, а там тишина. В офисе в субботу тихо. И так далее.... Прислушиваясь к себе я понял когда и как лучше работать а когда лучше убегать и работать (или не работать) еще где-то. Что вышло?


4 часовой заплыв. В дне их можно спокойно тройку раз получить. Эффективные. Сочные. Без прерываний. Это 12 часов. Но обычно хватает с головой и 2х. Это те же 8 часов. Только не в интервале с 9 до 18 с часом на обед. Нет. В сутках. Повторюсь. Эффективные. Сочные. Без прокрасинаций. По сути. По делу. Я как программист заметил, что у меня минимальный отрезок времени за который я могу что-то задемить (чтобы оно мне понравилось) как раз 4 часа +/-. Когда я это понял я стал укреплять эту свою стратегию. И вот чем.


Интернет нафиг.  Я либо 4 часа буду отвечать в скайпе в режиме суппорта. Либо выдерну интернет из ноутбука и буду заниматься чем-то еще. Тихо и спокойно. И не будет никаких позывов заглянуть в почту, на фейсбук, в твиттер, скайп... Соседа-перфораста тут уже нет. В квартире (или офисе, или кафешке, или на природе в парке у ручья) тишина и спокойствие. Осталось только заткнуть рот интернету. Что я и делаю. Всего на 4 часа. Там захочу погрузиться? Погружусь. Но сейчас как в старые добрые времена - инет только в кафешке. Что еще?


Заниматься только тем, что в кайф. Это одна из оснонвных несущих. С ее помощью можно работать даже 4 часа в день, и даже через день. Объясню почему. Из школы ты помнишь (или нет, не страшно) формулу кинетической энергии движущегося тела. Е = 1/2 * M * V^2. Секрет этой формулы в том, что если мы хотим увеличить энергию, то можно сделать это двумя путями. Увеличив массу и увеличив скорость тела. Тем кому с массой не сложилось с детства, могут выбрать боле эффективный путь - скорость. Это знал Дедушка Ли.  


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


Теперь если провести аналогию с успехом, или скажем с энергией успеха, то я нарисую такую формулу: Е = t * fun^2. Успех = время на фан в квадрате. Тут так же можно схитрить. Допустим есть проект с интересностью 1. Получается за 1 единицу времени я получу 1 единицу успеха. За 10 единиц времени - 10 единиц успеха. И так далее, в линейной зависимости. А что будет если интересность проекта увеличить в 10 раз? за 1 единицу времени я получу 100 единиц успеха. А если интересность проекта увеличить в 100 раз? Тогда за 1 единицу времени я получу уже 10000 (десять тысяч) единиц успеха. При интересности проекта в 1000, я уже миллионер. Это квадратическая зависимость. Она не намного сильнее линейной в начале пути, но потом она очень и очень. Потому я буду делать только то, что мне нравится, а то что не нравится полюблю. Что еще?

Потребительство. Не так давно мы с другом общались на тему того, что вроде как и айти но все как-то то же самое и то же самое... А нового и не будет ничего, пока мы не поднимем своим попы и не начнем писать что-то свое, что можно будет через неделю уже задэмить друзьям, а через месяц опубликовать в сети как бетту. Нет времени на это? Смотри абзац "Заниматься только тем, что в кайф" - времени много и не надо. Важно удовольствие получаемое в процессе. Чем его больше - тем больше и успех.

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


По чуть чуть. Если мое хобби принесет мне больше плюшек значит делай я его 24/7 я получу их еще больше. Нет. Перегоришь за неделю, а потом начнется рутина. И хорошо, если после месяца отходняка захочется вернуться в свое хобби. 4 часа в неделю на каждое дело на пике ХОЧУшности. Если взять что отрезков по 4 часа в дне 3, а дней в неделе 7. То потенциально можно заниматься в неделю 21 проектами. В их число, естественно, входит и семья и спорт/активный отдых и все, что нам нравится в жизни. А все остальное?


В топку. Не так давно ехали мы с друзьями и было сказано: туду - это список тех дел, которые я  не сделаю никогда. И фиг с ними. Если их не хочется делать, значит не пришло еще их время. Навязано рекламой, социумом, опытом еще чем-то... Не твое. Выпиши в ТУДУ и забудь думать. "Может быть как-нибудь" обычно называется этот список. Я понял, что не реализую всего того что генерит мой чердак каждый день, когда понял что через неделю идей в туду было на 2 листа A4, через месяц на 10... На 30 листах за два месяца я плюнул, удалил доку и начал с чистого листа. И это при том, что оттуда интенсивно все удалялось как выполненное.... В топку. Может быть, как-нибудь я себя клонирую, а может наконец-то команду обрету. Но не сейчас.... Так что только самое важное - то что хочется аж свербит. А если не свербит?


Аппетит приходит во время еды. Я выбиваюсь из своего правила 4 часа на 1 дело в неделю. Иногда получается все 6 часов. Обычно это получается тогда, когда я вроде как встал, вроде как ничего не хочется сутра. Лежу. Уже тело ломит - сколько можно дрыхнуть? Но пока не придет в голову идея не встаю. Или встаю, сажусь за комп и убеждаю себя, что займусь только 15 вот этим вот делом, которое давно откладываю... А потом как понеслось... Как понеслось... Я жеж и этот пост не хотел писать, а вот уже час пишу. И началось все с заметки на фейсбуке.



А еще помогай людям - нарушай закон подлости. Нетворкинг наше все. Как сказал один хороший человек - в одном племени все дети общие.


Как-то так...