Fixes #2333 Update ru.cljs (#2361)

Fixes #2333 Update ru.cljs (#2361)

* Update ru.cljs

--- src/status_im/translations/ru.cljs
+++ src/status_im/translations/ru.cljs
@@ -2,51 +2,67 @@

 (def translations
   {
-   ;common
+   ;;common
    :members-title                         "Участники"
    :not-implemented                       "!не реализовано"
    :chat-name                             "Имя чата"
    :notifications-title                   "Уведомления и звуки"
    :offline                               "Оффлайн"
+   :search-for                            "Искать..."
    :cancel                                "Отмена"
    :next                                  "Продолжить"
-
-   ;drawer
-   :invite-friends                        "Пригласить друзей"
-   :faq                                   "ЧАВО"
+   :open                                  "Открыть"
+   :description                           "Описание"
+   :url                                   "URL-адрес"
+   :type-a-message                        "Напишите сообщение..."
+   :type-a-command                        "Начинайте вводить команду..."
+   :error                                 "Ошибка"
+   :unknown-status-go-error               "Неизвестная status-go ошибка"
+   :node-unavailable                      "Нет запущенного ethereum узла"
+   :yes                                   "Да"
+   :no                                    "Нет"
+
+   :camera-access-error                   "Чтобы предоставить необходимое разрешение для камеры, пожалуйста, перейдите в настройки системы и убедитесь, что выбрано Status > Камера."
+   :photos-access-error                   "Чтобы предоставить необходимое разрешение для фото, пожалуйста, перейдите в настройки системы и убедитесь, что выбрано Status > Фотографии."
+
+   ;;drawer
    :switch-users                          "Переключить пользователей"
-
-   ;chat
+   :current-network                       "Текущая сеть"
+
+   ;;chat
    :is-typing                             "печатает"
    :and-you                               "и вы"
    :search-chat                           "Поиск по чату"
    :members                               {:one   "1 член"
                                            :other "{{count}} члена(ов)"
                                            :zero  "нет членов"}
-   :members-active                        {:one   "1 член, 1 активный"
-                                           :other "{{count}} члена(ов), {{count}} активных"
+   :members-active                        {:one   "1 член"
+                                           :other "{{count}} члена(ов)"
                                            :zero  "нет членов"}
+   :public-group-status                   "Публичный"
    :active-online                         "В сети"
    :active-unknown                        "Неизвестно"
    :available                             "Доступно"
    :no-messages                           "Нет сообщений"
    :suggestions-requests                  "Запросы"
    :suggestions-commands                  "Команды"
-
-   ;sync
+   :faucet-success                        "Запрос Faucet был получен"
+   :faucet-error                          "Ошибка запроса Faucet"
+
+   ;;sync
    :sync-in-progress                      "Синхронизация..."
    :sync-synced                           "Синхронизируется"

-   ;messages
-   :status-sending                        "Отправляется"
-   :status-pending                        "в ожидании"
+   ;;messages
+   :status-pending                        "В ожидании"
    :status-sent                           "Отправлено"
    :status-seen-by-everyone               "Просмотрено всеми"
    :status-seen                           "Просмотрено"
    :status-delivered                      "Доставлено"
    :status-failed                         "Ошибка"
-
-   ;datetime
+
+   ;;datetime
+   :datetime-ago-format                   "{{number}} {{time-intervals}} {{ago}}"
    :datetime-second                       {:one   "секунда"
                                            :other "секунды"}
    :datetime-minute                       {:one   "минута"
@@ -55,124 +71,148 @@
                                            :other "часы"}
    :datetime-day                          {:one   "день"
                                            :other "дни"}
-   :datetime-multiple                     "c"
    :datetime-ago                          "назад"
    :datetime-yesterday                    "вчера"
    :datetime-today                        "сегодня"

-   ;profile
+   ;;profile
    :profile                               "Профиль"
-   :report-user                           "ПОЖАЛОВАТЬСЯ НА ПОЛЬЗОВАТЕЛЯ"
+   :edit-profile                          "Редактировать профиль"
    :message                               "Сообщение"
-   :username                              "Имя пользователя"
    :not-specified                         "Не указано"
    :public-key                            "Публичный ключ"
    :phone-number                          "Номер телефона"
-   :email                                 "Электронная почта"
-   :profile-no-status                     "Нет статуса"
+   :update-status                         "Обновите свой статус..."
+   :add-a-status                          "Добавить статус..."
+   :status-prompt                         "Укажите свой статус. Использование #хэштегов поможет другим узнать о вас и рассказать о том, что у вас на уме"
    :add-to-contacts                       "Добавить в контакты"
-   :error-incorrect-name                  "Выберите другое имя"
-   :error-incorrect-email                 "Неправильная электронная почта"
+   :in-contacts                           "В контактах"
+   :remove-from-contacts                  "Удалить из контактов"
+   :start-conversation                    "Начать разговор"
+   :send-transaction                      "Отправить транзакцию"
+   :testnet-text                          "Вы находитесь в {{testnet}} Testnet. Не отправляйте реальный ETH или SNT на свой адрес"
+   :mainnet-text                          "Вы в Mainnet. Реальный ETH будет отправлен"

    ;;make_photo
    :image-source-title                    "Изображение профиля"
    :image-source-make-photo               "Сфотографировать"
    :image-source-gallery                  "Выбрать из галереи"
-   :image-source-cancel                   "Отмена"

    ;;sharing
    :sharing-copy-to-clipboard             "Скопировать"
    :sharing-share                         "Поделиться..."
    :sharing-cancel                        "Отмена"

-   ;sign-up
+   :browsing-title                        "Просматривать"
+   :browsing-browse                       "@browse"
+   :browsing-open-in-web-browser          "Открыть в веб-браузере"
+   :browsing-cancel                       "Отмена"
+
+   ;;sign-up
    :contacts-syncronized                  "Ваши контакты синхронизированы"
    :confirmation-code                     (str "Спасибо! Мы отправили вам СМС с кодом подтверждения."
                                                "Введите этот код для подтверждения своего номера телефона")
    :incorrect-code                        (str "Извините, код неправильный, введите еще раз")
-   :generate-passphrase                   (str "Я создам для вас парольную фразу, чтобы вы смогли восстановить ваш"
-                                               "доступ или войти с другого устройства")
-   :phew-here-is-your-passphrase          (str "*Уф*, это было непросто, вот ваша парольная фраза, *запишите ее и сохраните в надежном месте!* "
-                                               "Она будет нужна вам для восстановления аккаунта.")
-   :here-is-your-passphrase               (str "Вот ваша парольная фраза, *запишите ее и сохраните в надежном месте!* "
-                                               "Она будет нужна вам для восстановления аккаунта.")
-   :written-down                          "Убедитесь, что вы записали ее в надежном месте"
-   :phone-number-required                 "Нажмите сюда для ввода своего номера телефона и поиска своих друзей"
+   :phew-here-is-your-passphrase          "*Уф*, это было непросто, вот ваша парольная фраза, *запишите ее и храните в надежном месте!* Она будет нужна вам для восстановления аккаунта."
+   :here-is-your-passphrase               "Вот ваша парольная фраза, *запишите ее и храните в надежном месте!* Она будет нужна вам для восстановления аккаунта."
+   :here-is-your-signing-phrase           "Вот ваша фраза подписи. Вы будете использовать ее для проверки достоверности своих транзакций. *Запишите ее и храните в безопасности!*"
+   :phone-number-required                 "Нажмите сюда для ввода своего номера телефона и я найду ваших друзей."
+   :shake-your-phone                      "Найдена ошибка или есть предложение? Просто ~потрясите~ свой телефон!"
    :intro-status                          "Пообщайтесь со мной в чате, чтобы настроить свой аккаунт и изменить свои настройки!"
-   :intro-message1                        "Добро пожаловать в Статус\nНажмите на это сообщение, чтобы установить пароль и начать!"
+   :intro-message1                        "Добро пожаловать в Status\nНажмите на это сообщение, чтобы установить пароль и начать!"
    :account-generation-message            "Секундочку, мне нужно выполнить безумно сложные расчеты для создания вашего аккаунта!"
-
-   ;chats
+   :move-to-internal-failure-message      "Нам нужно переместить некоторые важные файлы из внешнего хранилища во внутреннее. Для этого нам нужно ваше разрешение. В следующих версиях мы не будем использовать внешнее хранилища."
+   :debug-enabled                         "Запущен сервер отладки! Теперь вы можете выполнить * status-dev-cli scan *, чтобы найти сервер с вашего компьютера в той же сети."
+
+   ;;phone types
+   :phone-e164                            "Международный 1"
+   :phone-international                   "Международный 2"
+   :phone-national                        "Государственный"
+   :phone-significant                     "Простой"
+
+   ;;chats
    :chats                                 "Чаты"
-   :new-chat                              "Новый чат"
+   :delete-chat                           "Удалить чат"
    :new-group-chat                        "Новый групповой чат"
-
-   ;discover
+   :new-public-group-chat                 "Присоединиться к публичному чату"
+   :edit-chats                            "Редактировать чаты"
+   :search-chats                          "Поиск чатов"
+   :empty-topic                           "Пустая тема"
+   :topic-format                          "Неверный формат [a-z0-9\\-]+"
+   :public-group-topic                    "Тема"
+
+   ;;discover
    :discover                              "Поиск"
    :none                                  "Нет"
    :search-tags                           "Введите теги для поиска сюда"
    :popular-tags                          "Популярные теги"
-   :recent                                "Последние"
+   :recent                                "Последние статусы"
+   :no-statuses-found                     "Статусы не обнаружены"
+   :chat                                  "Чат"
+   :all                                   "Все"
+   :public-chats                          "Публичные чаты"
+   :soon                                  "Скоро"
+   :public-chat-user-count                "{{count}} людей"
+   :dapps                                 "ÐApps"
+   :dapp-profile                          "ÐApp профиль"
    :no-statuses-discovered                "Статусы не обнаружены"
-
-   ;settings
+   :no-statuses-discovered-body           "Когда кто-то создаст\nстатус, вы увидите его здесь."
+   :no-hashtags-discovered-title          "#хэштеги не обнаружены"
+   :no-hashtags-discovered-body           "Когда #хэштег станет\nпопулярным, вы увидите его здесь."
+
+   ;;settings
    :settings                              "Настройки"

-   ;contacts
+   ;;contacts
    :contacts                              "Контакты"
    :new-contact                           "Новый контакт"
+   :delete-contact                        "Удалить контакт"
+   :delete-contact-confirmation           "Этот контакт будет удален из ваших контактов"
+   :remove-from-group                     "Удалить из группы"
    :edit-contacts                         "Редактирование контактов"
-   :show-all                              "ПОКАЗАТЬ ВСЕ"
-   :contacts-group-dapps                  "ÐApps"
-   :contacts-group-people                 "Люди"
-   :contacts-group-new-chat               "Начать новый чат"
+   :search-contacts                       "Поиск контактов"
+   :contacts-group-new-chat               "Новый групповой чат"
+   :choose-from-contacts                  "Выбрать из контактов"
    :no-contacts                           "Пока нет контактов"
    :show-qr                               "Показать QR"
    :enter-address                         "Ввести адрес"
-
-   ;group-settings
+   :more                                  "Больше"
+
+   ;;group-settings
    :remove                                "Удалить"
    :save                                  "Сохранить"
-   :change-color                          "Изменить цвет"
+   :delete                                "Удалить"
    :clear-history                         "Очистить историю"
-   :delete-and-leave                      "Удалить и оставить"
+   :mute-notifications                    "Отключить звук в оповещениях"
+   :leave-chat                            "Выйти из чата"
    :chat-settings                         "Настройки чата"
    :edit                                  "Изменить"
    :add-members                           "Добавить членов"
-   :blue                                  "Синий"
-   :purple                                "Фиолетовый"
-   :green                                 "Зеленый"
-   :red                                   "Красный"
-
-   ;commands
-   :money-command-description             "Отправить деньги"
-   :location-command-description          "Отправить местоположение"
-   :phone-command-description             "Отправить номер телефона"
-   :phone-request-text                    "Запрос номера телефона"
-   :confirmation-code-command-description "Отправить код подтверждения"
-   :confirmation-code-request-text        "Запрос кода подтверждения"
-   :send-command-description              "Отправить местоположение"
-   :request-command-description           "Отправить запрос"
-   :keypair-password-command-description  ""
-   :help-command-description              "Помощь"
-   :request                               "Запрос"
+
+   ;;commands
    :chat-send-eth                         "{{amount}} ETH"
-   :chat-send-eth-to                      "{{amount}} ETH в адрес {{chat-name}}"
-   :chat-send-eth-from                    "{{amount}} ETH от {{chat-name}}"
-
-   ;new-group
-   :group-chat-name                       "Имя чата"
-   :empty-group-chat-name                 "Введите имя"
-   :illegal-group-chat-name               "Выберите другое имя"
+
+   ;;location command
+   :your-current-location                 "Ваше текущее местоположение"
+   :places-nearby                         "Места поблизости"
+   :search-results                        "Результаты поиска"
+   :dropped-pin                           "Выбранное местоположение"
+   :location                              "Местоположение"
+   :open-map                              "Открыть Карту"
+   :sharing-copy-to-clipboard-address     "Скопировать адрес"
+   :sharing-copy-to-clipboard-coordinates "Копировать координаты"
+
+   ;;new-group
    :new-group                             "Новая группа"
-   :group-name                            "Название группы"
    :reorder-groups                        "Упорядочить группы"
-
-   ;participants
-   :add-participants                      "Добавить участников"
-   :remove-participants                   "Удалить участников"
-
-   ;protocol
+   :edit-group                            "Изменить группу"
+   :delete-group                          "Удалить группу"
+   :delete-group-confirmation             "Эта группа будет удалена из ваших групп. Это не повлияет на ваши контакты"
+   :delete-group-prompt                   "Это не повлияет на ваши контакты"
+   :contact-s                             {:one   "контакт"
+                                           :other "контакты"}
+
+   ;;protocol
    :received-invitation                   "получил(а) приглашение в чат"
    :removed-from-chat                     "удалил(а) вас из группового чата"
    :left                                  "осталось"
@@ -180,130 +220,145 @@
    :removed                               "удален(а)"
    :You                                   "Вы"

-   ;new-contact
+   ;;new-contact
    :add-new-contact                       "Добавить новый контакт"
-   :import-qr                             "Импорт"
    :scan-qr                               "Сканировать QR"
    :name                                  "Имя"
-   :whisper-identity                      "Скрытая личность"
-   :address-explication                   "Может быть, здесь должен быть какой-то текст, поясняющий адрес и то, где его искать"
-   :enter-valid-address                   "Введите действительный адрес или сканируйте QR-код"
+   :address-explication                   "Ваш публичный ключ используется для создания вашего адреса в Ethereum и представляет собой ряд цифр и букв. Вы можете легко найти его в своем профиле"
    :enter-valid-public-key                "Введите действительный публичный ключ или сканируйте QR-код"
    :contact-already-added                 "Контакт уже добавлен"
    :can-not-add-yourself                  "Вы не можете добавить себя"
    :unknown-address                       "Неизвестный адрес"

-
-   ;login
+   ;;login
    :connect                               "Подключиться"
    :address                               "Адрес"
    :password                              "Пароль"
-   :login                                 "Вход"
+   :sign-in-to-status                     "Войти в Status"
+   :sign-in                               "Войти"
    :wrong-password                        "Неверный пароль"
-
-   ;recover
-   :recover-from-passphrase               "Восстановление с помощью парольной фразы"
-   :recover-explain                       "Введите парольную фразу вместо вашего пароля для восстановления доступа"
+   :enter-password                        "Введите пароль"
+
+   ;;recover
    :passphrase                            "Парольная фраза"
    :recover                               "Восстановить"
-   :enter-valid-passphrase                "Введите парольную фразу"
-   :enter-valid-password                  "Введите пароль"
-
-   ;accounts
-   :recover-access                        "Восстановить доступ"
-   :add-account                           "Добавить аккаунт"
-
-   ;wallet-qr-code
+   :twelve-words-in-correct-order         "12 слов в правильном порядке"
+
+   ;;accounts
+   :recover-access                        "Восстановление доступа"
+   :create-new-account                    "Создать новый аккаунт"
+
+   ;;wallet-qr-code
    :done                                  "Готово"
-   :main-wallet                           "Основной кошелек"
-
-   ;validation
-   :invalid-phone                         "Неверный номер телефона"
+
+   ;;validation
+   :invalid-phone                         "Неправильный номер телефона"
    :amount                                "Сумма"
-   :not-enough-eth                        (str "Не хватает ETH на балансе "
-                                               "({{balance}} ETH)")
-   ;transactions
-   :confirm-transactions                  {:one   "Подтвердить транзакцию"
-                                           :other "Подтвердите {{count}} транзакции(ий)"
-                                           :zero  "Нет транзакций"}
-   :status                                "Статус"
-   :pending-confirmation                  "В ожидании подтверждения"
+
+   ;;transactions
+   :confirm                               "Подтвердить"
+   :transaction                           "Транзакция"
+   :unsigned-transaction-expired          "Неподписанная транзакция истекла"
+   :status                                "Status"
    :recipient                             "Получатель"
-   :one-more-item                         "Еще одна позиция"
-   :fee                                   "Комиссия"
-   :value                                 "Сумма"
-
-   ;:webview
+   :to                                    "Кому"
+   :from                                  "От"
+   :data                                  "Данные"
+   :got-it                                "Понятно"
+   :block                                 "Блок"
+   :hash                                  "Хеш"
+   :gas-limit                             "Лимит Гaзa"
+   :gas-price                             "Цена на Газ"
+   :gas-used                              "Использованный Газ"
+   :cost-fee                              "Стоимость/Комиссия"
+   :nonce                                 "Nonce"
+   :confirmations                         "Подтверждения"
+   :confirmations-helper-text             "Пожалуйста, дождитесь как минимум 12-ти подтверждений, чтобы убедиться, что транзакция обработана безопасно"
+   :copy-transaction-hash                 "Копировать транзакционный хеш"
+   :open-on-etherscan                     "Открыть ссылку на Etherscan.io"
+
+   ;;webview
    :web-view-error                        "ой, ошибка"

-   :confirm                               "Подтвердить"
-   :phone-national                        "Государственный"
-   :transactions-confirmed                {:one   "Транзакция подтверждена"
-                                           :other "Подтверждено {{count}} транзакции(й)"
-                                           :zero  "Нет подтвержденных транзакций"}
-   :public-group-topic                    "Тема"
-   :debug-enabled                         "Запущен сервер отладки! Теперь вы можете добавить DApp, выполнив со своего компьютера *status-dev-cli scan*"
-   :new-public-group-chat                 "Присоединиться к общему чату"
-   :datetime-ago-format                   "{{number}} {{time-intervals}} {{ago}}"
-   :share-qr                              "Поделиться QR"
-   :feedback                              "Есть отзыв?\nВстряхните телефон!"
-   :twelve-words-in-correct-order         "12 слов в нужном порядке"
-   :remove-from-contacts                  "Удалить из контактов"
-   :delete-chat                           "Удалить чат"
-   :edit-chats                            "Изменить чаты"
-   :sign-in                               "Вход"
-   :create-new-account                    "Создать новый аккаунт"
-   :sign-in-to-status                     "Войти в Статус"
-   :got-it                                "Понятно"
-   :move-to-internal-failure-message      "Нам необходимо перенести некоторые важные файлы из внешнего хранилища во внутреннее. Для этого нам нужно ваше разрешение. В следующих версиях мы не будем использовать внешнее хранилище."
-   :edit-group                            "Изменить группу"
-   :delete-group                          "Удалить группу"
-   :browsing-title                        "Просматривать"
-   :browsing-cancel                       "Отмена"
-   :faucet-success                        "Заявка на сборщик получена"
-   :choose-from-contacts                  "Выбрать из контактов"
-   :phone-e164                            "Международная 1"
-   :remove-from-group                     "Удалить из группы"
-   :search-contacts                       "Поиск контактов"
-   :transaction                           "Транзакция"
-   :public-group-status                   "Общий"
-   :leave-chat                            "Выйти из чата"
-   :start-conversation                    "Начать разговор"
-   :topic-format                          "Неверный формат [a-z0-9\\-] +"
-   :faucet-error                          "Ошибка заявки на сборщик"
-   :phone-significant                     "Значительное"
-   :search-for                            "Искать..."
-   :phone-international                   "Международная 2"
-   :send-transaction                      "Отправить транзакцию"
-   :delete-contact                        "Удалить контакт"
-   :mute-notifications                    "Отключить звук в оповещениях"
-
-
-   :contact-s                             {:one   "контакт"
-                                           :other "контакты"}
-   :from                                  "От"
-   :search-chats                          "Поиск чатов"
-   :in-contacts                           "В контактах"
-
-   :type-a-message                        "Напишите сообщение..."
-   :type-a-command                        "Начинайте вводить команду..."
-   :shake-your-phone                      "Нашли ошибку или есть предложение? Просто ~потрясите~ телефон!"
-   :status-prompt                         "Создайте статус, чтобы люди знали о том, что вы предлагаете. Можно также использовать #хэштеги."
-   :add-a-status                          "Добавьте статус..."
-   :error                                 "Ошибка..."
-   :more                                  "Больше"
-   :no-statuses-found                     "Статусы не найдены"
-   :swow-qr                               "Показать QR-код"
-   :browsing-open-in-web-browser          "Открыть в веб-браузере"
-   :delete-group-prompt                   "Это не повлияет на контакты"
-   :edit-profile                          "Редактировать профиль"
-
-
-   :enter-password-transactions           {:one   "Подтвердите транзакцию, указав свой пароль"
-                                           :other "Подтвердите транзакции, указав свой пароль"}
-   :unsigned-transactions                 "Неподписанные транзакции"
-   :empty-topic                           "Пустая тема"
-   :to                                    "Кому"
-   :group-members                         "Участники группы"
-   :estimated-fee                         "Примерная комиссия"
-   :data                                  "Дата"})
+   ;;testfairy warning
+   :testfairy-title                       "Предупреждение!"
+   :testfairy-message                     "Вы используете приложение, установленное из ночной сборки. Для целей тестирования эта сборка включает в себя запись сеанса, если используется соединение Wi-Fi, так что все ваши взаимодействия с этим приложением сохраняются (как видео и логи) и могут использоваться нашей командой разработчиков для изучения возможных проблем. Сохраненные видео / логи не включают в себя ваши пароли. Запись выполняется только в том случае, если приложение установлено из ночной сборки. Ничего не записывается, если приложение установлено из PlayStore или TestFlight."
+   ;; wallet
+   :wallet                                "Кошелек"
+   :wallets                               "Кошельки"
+   :your-wallets                          "Ваши кошельки"
+   :main-wallet                           "Основной Кошелек"
+   :wallet-error                          "Ошибка при загрузке данных"
+   :wallet-send                           "Отправить"
+   :wallet-request                        "Запрос"
+   :wallet-exchange                       "Обмен"
+   :wallet-assets                         "Активы"
+   :wallet-add-asset                      "Добавить актив"
+   :wallet-total-value                    "Общая стоимость"
+   :wallet-settings                       "Настройки кошелька"
+   :signing-phrase-description            "Подпишите транзакцию, введя свой пароль. Убедитесь, что слова выше соответствуют вашей секретной фразе подписи"
+   :wallet-insufficient-funds             "Недостаточно средств"
+   :request-transaction                   "Запрос транзакции"
+   :send-request                          "Послать запрос"
+   :share                                 "Поделиться"
+   :eth                                   "ETH"
+   :currency                              "Валюта"
+   :usd-currency                          "USD"
+   :transactions                          "Транзакции"
+   :transaction-details                   "Детали транзакции"
+   :transaction-failed                    "Не удалось выполнить транзакцию"
+   :transactions-sign                     "Подписать"
+   :transactions-sign-all                 "Подписать все"
+   :transactions-sign-transaction         "Подписать транзакцию"
+   :transactions-sign-later               "Подписать позже"
+   :transactions-delete                   "Удалить транзакцию"
+   :transactions-delete-content           "Транзакция будет удалена из списка 'Неподписанные'"
+   :transactions-history                  "История"
+   :transactions-unsigned                 "Неподписанные"
+   :transactions-history-empty            "В вашей истории еще нет транзакций"
+   :transactions-unsigned-empty           "У вас нет никаких неподписанных транзакций"
+   :transactions-filter-title             "Фильтры Истории"
+   :transactions-filter-tokens            "Токены"
+   :transactions-filter-type              "Тип"
+   :transactions-filter-select-all        "Выбрать все"
+   :view-transaction-details              "Посмотреть детали транзакции"
+   :transaction-description               "Пожалуйста, подождите как минимум 12 подтверждений, чтобы убедиться, что транзакция обработана безопасно"
+   :transaction-sent                      "Транзакция отправлена"
+   :transaction-moved-text                "Транзакция будет находиться в списке 'Неподписанные' в течение 5 минут"
+   :transaction-moved-title               "Транзакция перемещена"
+   :sign-later-title                      "Подписать транзакцию позже?"
+   :sign-later-text                       "Откройте историю транзакций, чтобы подписать эту транзакцию"
+   :not-applicable                        "Не применимо для неподписанных транзакций"
+
+   ;; Wallet Send
+   :wallet-choose-recipient               "Выберите Получателя"
+   :wallet-choose-from-contacts           "Выберите Из Контактов"
+   :wallet-address-from-clipboard         "Использовать Адрес Из Буфера Обмена"
+   :wallet-invalid-address                "Недействительный адрес: \n {{data}}"
+   :wallet-browse-photos                  "Просмотреть Фотографии"
+   :validation-amount-invalid-number      "Сумма не действительна"
+   :validation-amount-is-too-precise      "Слишком много чисел после запятой. Наименьшая сумма, которую вы можете отправить это 1 Wei (1x10^-18 ETH)"
+
+
+
+   ;; network settings
+   :new-network                           "Новая сеть"
+   :add-network                           "Добавить сеть"
+   :add-new-network                       "Добавить новую сеть"
+   :existing-networks                     "Существующие сети"
+   :add-json-file                         "Добавить JSON файл"
+   :paste-json-as-text                    "Вставить JSON как текст"
+   :paste-json                            "Вставить JSON"
+   :specify-rpc-url                       "Укажите RPC URL-адрес"
+   :edit-network-config                   "Редактировать конфигурацию сети"
+   :connected                             "Подключен"
+   :process-json                          "Обработать JSON"
+   :error-processing-json                 "Ошибка обработки JSON"
+   :rpc-url                               "RPC URL-адрес"
+   :remove-network                        "Удалить сеть"
+   :network-settings                      "Настройки сети"
+   :edit-network-warning                  "Будьте осторожны, изменение настроек сети может сделать её недоступной для вас"
+   :connecting-requires-login             "Подключение к другой сети требует входа в систему"
+   :close-app-title                       "Предупреждение!"
+   :close-app-content                     "Приложение остановится и закроется. При повторном открытии, будет использоваться выбранная сеть"
+   :close-app-button                      "Подтвердить"})


Pretty much working now.

Pretty much working now.

--- clojure/majority-element/src/majority_element/core.clj
+++ clojure/majority-element/src/majority_element/core.clj
@@ -1,14 +1,33 @@
 (ns majority-element.core
   (:gen-class))

+(require '[clojure.string :as str])
+
+(defn parse-elements
+  "Parses the elements in the first line of a CSV file"
+  [filename]
+  (map read-string (str/split (slurp filename) #","))
+  )
+
+(defn add-or-increment
+  "Given a map and an element, looks up the element in the map.  If the element isn't present, adds it with a value of 1, otherwise increments the existing value."
+  [element-map element]
+  (if (get element-map element)
+    (update-in element-map [element] inc)
+    (assoc element-map element 1)
+    )
+  )
+
+(defn majority-element
+  "Given an input list of integers, returns either the one that occurs greater than 50% of the time in the list if it exists, otherwise nil."
+  [elements]
+  (def count-map (reduce add-or-increment {} elements))
+  (def result (filter (fn [[k v]] (> v (/ (count elements) 2))) count-map))
+  (first (keys result))
+  )
+
 (defn -main
-  "I don't do a whole lot ... yet."
+  "Finds the majority element of a list of elements (one occurring > 50% of the time in the list), if one exists."
   [& args]
-  (println "I'm a little teapot!"))
-
-(println "Cleanliness is next to godliness")
-
-(defn train
-  []
-  (println "Choo choo!"))
-
+  (println (majority-element (parse-elements (first args))))
+  )


Remove unused.

Remove unused.

--- src/stuttaford/radiant/schema.cljs
+++ src/stuttaford/radiant/schema.cljs
@@ -1,22 +0,0 @@
-(ns stuttaford.radiant.schema
-  (:require [datascript :as d]
-            [om-tools.core :refer-macros [defcomponentk]]
-            [om-bootstrap.random :refer [label]]
-            [om-bootstrap.table :refer [table]]
-            [sablono.core :as html :refer-macros [html]]
-            [stuttaford.radiant.components :as components]
-            [stuttaford.radiant.model :as model]))
-
-(defcomponentk schema [[:data {current-db nil}] owner]
-  (render-state [_ state]
-    (html
-     [:div
-      (if current-db
-        (for [schema (model/schema-for-db current-db)]
-          [:span.schema
-           (pr-str (:db/ident schema))
-           (when (= :db.type/ref (:db/valueType schema))
-             (label {:bs-style "primary"} "REF"))
-           (when (= :db.cardinality/many (:db/cardinality schema))
-             (label {:bs-style "primary"} "MANY"))])
-        "No database.")])))


Add an (optional) callback to defregistry

This allows to hook into registration and unregistration events
and perform actions in reaction to them.

--- src/main/workflo/macros/registry.clj
+++ src/main/workflo/macros/registry.clj
@@ -20,6 +20,9 @@
    utility functions that are defined implicitly.

    (defregistry* 'command)
+   (defregistry* 'command
+                 (fn [event entity-name]
+                   ...))

    will result in the following functions to be defined:

@@ -29,8 +32,10 @@
    (defn reset-registered-commands! [] ...)
    (defn resolve-command [name] ...)."
   ([name]
-   (defregistry* name nil))
+   (defregistry* name nil nil))
   ([name env]
+   (defregistry* name nil nil))
+  ([name callback env]
    (let [registry-sym   (symbol (str "+" name "-registry+"))
          register-sym   (symbol (str "register-" name "!"))
          unregister-sym (symbol (str "unregister-" name "!"))
@@ -42,9 +47,13 @@
         (defonce ^:private ~registry-sym (atom (sorted-map)))
         (defn ~register-sym
           [~'name ~'def]
-          (swap! ~registry-sym assoc ~'name ~'def))
+          (swap! ~registry-sym assoc ~'name ~'def)
+          ~@(when callback
+              `((~callback :register ~'name))))
         (defn ~unregister-sym
           [~'name]
+          ~@(when callback
+              `((~callback :unregister ~'name)))
           (swap! ~registry-sym dissoc ~'name))
         (defn ~registered-sym
           []
@@ -64,5 +73,7 @@
 (defmacro defregistry
   "Defines a registry with the given name. See defregistry* for
    more information."
-  [name]
-  (defregistry* name &env))
+  ([name]
+   (defregistry* name &env))
+  ([name callback]
+   (defregistry* name callback &env)))


Disable input form if user selected data from search

--- src/discuss/views/add.cljs
+++ src/discuss/views/add.cljs
@@ -38,7 +38,8 @@
                                        :onChange #(do (om/update-state! this assoc :statement (.. % -target -value))
                                                       (search/search statement))
                                        :value (or (:text selected-search) statement "")
-                                       :placeholder (t :discussion :add-reason-placeholder)}]
+                                       :placeholder (t :discussion :add-reason-placeholder)
+                                       :disabled (not (nil? selected-search))}]
                  (when-not (nil? selected-search)
                    [:span.input-group-addon.pointer {:onClick search/remove-selected-search-result!}
                     (vlib/fa-icon "fa-times")])]
@@ -96,7 +97,8 @@
                                             :onChange #(do (om/update-state! this assoc :reason (.. % -target -value))
                                                            (search/search reason))
                                             :value (or (:text selected-search) reason "")
-                                            :placeholder (t :discussion :add-reason-placeholder)}]
+                                            :placeholder (t :discussion :add-reason-placeholder)
+                                            :disabled (not (nil? selected-search))}]
                       (when-not (nil? selected-search)
                         [:span.input-group-addon.pointer {:onClick search/remove-selected-search-result!}
                          (vlib/fa-icon "fa-times")])]


Save and load. Load still in progress.

Save and load. Load still in progress.

--- src/divergence/system.cljs
+++ src/divergence/system.cljs
@@ -18,23 +18,21 @@

 (def serial-data (atom ""))

-(defn save-to-local-db []
+(defn save-to-local-db [data]
   ;(js/alert @serial-data)
-  (.setItem js/localStorage "dm" @serial-data)
+  (.setItem js/localStorage "dm" data)
   )

 (defn serialize [entities]
   (doseq [e entities]
-    (if (= ":bunny" (pr-str(@e :name)))
-      (do(reset! serial-data @e)
-         (save-to-local-db @e)))))
+    (if (= ":bunny" (pr-str (@e :name)))
+      (save-to-local-db (dissoc @e :ref :sprite :stage)))))

 (defn deserialize [entities]
-  ;(reset! serial-data (.getItem js/localStorage "dm")) <-- This is for loading from local storage. Not working.
   ;(js/alert @serial-data)
-   (doseq [e entities]
-     (if (= ":bunny" (pr-str(@e :name)))
-      (reset! e @serial-data))))
+   (doseq [e entities
+           :when (= :bunny (@e :name))]
+     (reset! e (read-string (.getItem js/localStorage "dm")))))

 (defn as [entity k]
   (@entity k))
@@ -229,7 +227,6 @@

-
 (defn create-text [entities]
   (doseq [e entities]
     (let [style (get-in @e [:text :style])


Fix issue with malformed query strings resulting in an exception

--- src/cfpb/qu/resources.clj
+++ src/cfpb/qu/resources.clj
@@ -139,6 +139,10 @@
         href (url-like (if-let [query-string (:query-string request)]
                          (str base-href "?" query-string)
                          base-href))
+        ;; If the query string is malformed, url-like will return nil.
+        ;; We prevent that by using the base-href in that case.
+        href (or href
+                 (url-like base-href))
         result (:result query)
         clauses (map (comp keyword :key) views/clauses)
         page (:page query)]


Fix drag to non-movable square

Fix drag to non-movable square

--- src/chessground/ctrl.cljs
+++ src/chessground/ctrl.cljs
@@ -14,18 +14,6 @@
   (when function (apply function (map clj->js args))))

 (defn- noop [] nil)
-
-(defn select-square [state key]
-  (if-let [orig (:selected state)]
-    (if (not (= orig key))
-      (move-piece state [orig key])
-      [state noop])
-    (if (and (chess/get-piece (:chess state) key) (data/is-movable? state key))
-      (move-start state key)
-      [state
-       (fn [$app chans]
-         (show/selected $app nil)
-         (show/dests $app nil))])))

 (defn move-start [state orig]
   "A move has been started, either by clicking on a piece, or dragging it"
@@ -52,7 +40,25 @@
       (if (= orig dest)
         [state (fn [$app chans] (show/move $app orig dest))]
         (let [new-state (dissoc state :selected)]
-          (select-square new-state dest)))))
+          (if (and (chess/get-piece (:chess new-state) dest) (data/is-movable? new-state dest))
+            (move-start state dest)
+              [new-state
+              (fn [$app chans]
+                (show/un-move $app orig)
+                (show/selected $app nil)
+                (show/dests $app nil))])))))
+
+(defn select-square [state key]
+  (if-let [orig (:selected state)]
+    (if (not (= orig key))
+      (move-piece state [orig key])
+      [state noop])
+    (if (and (chess/get-piece (:chess state) key) (data/is-movable? state key))
+      (move-start state key)
+      [state
+       (fn [$app chans]
+         (show/selected $app nil)
+         (show/dests $app nil))])))

 (defn set-orientation [state orientation]
   (if (common/set-contains? chess/colors orientation)


change `cljs.analyzer/parse-ns` so that it also accepts a symbol

--- src/clj/cljs/analyzer.clj
+++ src/clj/cljs/analyzer.clj
@@ -1820,7 +1820,10 @@
   ([src opts] (parse-ns src nil opts))
   ([src dest opts]
     (env/ensure
-      (let [namespaces' (::namespaces @env/*compiler*)
+      (let [src (if (symbol? src)
+                  (io/resource (util/ns->relpath src))
+                  src)
+            namespaces' (::namespaces @env/*compiler*)
             ret
             (binding [*cljs-ns* 'cljs.user
                       *macro-infer*


fix .foo/bar and foo/bar. macroexpansion, was dropping ns

--- src/clj/cljs/compiler.clj
+++ src/clj/cljs/compiler.clj
@@ -614,7 +614,7 @@
       (if-let [mac (and (symbol? op) (get-expander op env))]
         (apply mac form env (rest form))
         (if (symbol? op)
-          (let [opname (name op)]
+          (let [opname (str op)]
             (cond
              (= (first opname) \.) (let [[target & args] (next form)]
                                      (list* '. target (symbol (subs opname 1)) args))


fix giant tagtime log imports

fix giant tagtime log imports

--- src/clj/tictag/server.clj
+++ src/clj/tictag/server.clj
@@ -20,7 +20,8 @@
             [tictag.jwt :as jwt]
             [tictag.schemas :as schemas]
             [clojure.spec.alpha :as s]
-            [tictag.tagtime :as tagtime]))
+            [tictag.tagtime :as tagtime]
+            [taoensso.timbre :as timbre]))

 (taoensso.timbre/refer-timbre)
 (def wtf (f/formatter "yyyy-MM-dd HH:mm:SS"))
@@ -312,18 +313,18 @@
             user (jwt/unsign jwt token)]
         (handler (assoc req :user-id (:user-id user)))))))

-(defn tagtime-import [{:keys [db]} {:keys [params user-id]}]
-  (taoensso.timbre/logged-future
-   (if-let [parsed (tagtime/parse user-id (:tagtime-log params))]
-     (db/insert-tagtime-data db parsed)
-     (debugf "Invalid tagtime data received from user-id %d" user-id)))
-  (response {:accepted true}))
-
 (defn tagtime-import-from-file [{:keys [db]} {:keys [multipart-params user-id]}]
   (taoensso.timbre/logged-future
    (debug multipart-params)
-   (if-let [parsed (tagtime/parse user-id (slurp (get-in multipart-params ["tagtime-log" :tempfile])))]
-     (db/insert-tagtime-data db parsed)
+   (if-let [parsed-all (seq (partition-all 1000
+                                           (tagtime/parse user-id
+                                                          (slurp
+                                                           (get-in multipart-params
+                                                                   ["tagtime-log" :tempfile])))))]
+     (doseq [parsed parsed-all]
+       (do
+         (timbre/debugf "adding %d pings to user %d" (count parsed) user-id)
+         (db/insert-tagtime-data db parsed)))
      (debugf "Invalid tagtime data received from user-id %d" user-id)))
   (response {:accepted true}))

@@ -347,7 +348,6 @@
    (GET "/about" _ (index component))
    (GET "/settings" _ (index component))
    (context "/api" []
-            (POST "/tagtime" _ (partial tagtime-import component))
             (PUT "/tagtime" _ (partial tagtime-import-from-file component))
             (GET "/timezones" _ (partial timezone-list component))
             (GET "/user/me" _ (partial my-user component))


Add explanation to info exception.

Add explanation to info exception.

--- src/cljam/io/vcf/util.clj
+++ src/cljam/io/vcf/util.clj
@@ -40,7 +40,10 @@
               {}
               (map (fn [ss]
                      (let [[k vs] (cstr/split ss #"\=" 2)]
-                       [(keyword k) ((parser-map k) vs)])))))))))
+                       (if-let [parser (parser-map k)]
+                         [(keyword k) (parser vs)]
+                         (throw (ex-info (str "Undeclared INFO, " k ".")
+                                         {:info ss}))))))))))))

 (defn info-stringifier
   "Returns a stringifier function of INFO field.


Filtering arena messages on client

Filtering arena messages on client

--- src/cljs/cyrats/core.cljs
+++ src/cljs/cyrats/core.cljs
@@ -109,12 +109,10 @@

 (rum/defc arena-frame
   [state arena-id]
-  (log/debug "STATE " state)
   [:div {:class "arena"}
-   (for [x (state :messages)]
-     [:p "Message: " (:payload x)]
-     )
-   ])
+   (for [x (state :messages)
+         :when (= arena-id (:arena-id x))]
+     [:p "Message: " (:payload x)])])

 (rum/defc stub-frame
   [_]
@@ -162,7 +160,7 @@
                                         (match
                                           [(state :page)]
                                           [[:arena arena-id]] (arena/subscribe-arena arena-id)
-                                        :else nil))
+                                          :else nil))
            )

 (refresh @STATE)


New indentation from clojure-mode 4.0.0

New indentation from clojure-mode 4.0.0

--- src/cljs/fatlip/core.cljs
+++ src/cljs/fatlip/core.cljs
@@ -157,19 +157,19 @@
   [graph node]
   (loop [graph graph
          characters (:characters node)]
-     (if (empty? characters)
-       graph
-       (let [character (first characters)
-             last-node (-> graph :last-nodes-by-character character)
-             [g c] (if last-node
-                     (let [last-node-characters (-> graph
-                                                    :last-nodes-by-node
-                                                    ((:id last-node) #{}))
-                           edge-characters (vec (set/intersection last-node-characters characters))
-                           g (process-edge-characters graph last-node node edge-characters)]
-                       [g (set/difference characters last-node-characters)])
-                     [graph (disj characters character)])]
-         (recur g c)))))
+    (if (empty? characters)
+      graph
+      (let [character (first characters)
+            last-node (-> graph :last-nodes-by-character character)
+            [g c] (if last-node
+                    (let [last-node-characters (-> graph
+                                                   :last-nodes-by-node
+                                                   ((:id last-node) #{}))
+                          edge-characters (vec (set/intersection last-node-characters characters))
+                          g (process-edge-characters graph last-node node edge-characters)]
+                      [g (set/difference characters last-node-characters)])
+                    [graph (disj characters character)])]
+        (recur g c)))))

 (defn add-node
@@ -463,15 +463,15 @@
   "Counts the sub-crossings that result from adding a single sub-edge
   to the accumulator tree"
   ([tree index]
-     (single-edge-sub-crossings tree index 0))
+   (single-edge-sub-crossings tree index 0))
   ([tree index crossings]
-     (if (zero? index)
-       [tree crossings]
-       (let [parent-index (quot (dec index) 2)
-             real-right-index parent-index]
-         (if (odd? index)
-           (recur tree parent-index (+ crossings (get tree real-right-index)))
-           (recur (update-in tree [real-right-index] inc) parent-index crossings))))))
+   (if (zero? index)
+     [tree crossings]
+     (let [parent-index (quot (dec index) 2)
+           real-right-index parent-index]
+       (if (odd? index)
+         (recur tree parent-index (+ crossings (get tree real-right-index)))
+         (recur (update-in tree [real-right-index] inc) parent-index crossings))))))

 (defn count-sub-crossings-single-node
@@ -643,50 +643,50 @@
     counting and marking to be parallelized, whereas the ordering is inherently
     serial."
   ([sparse-graph]
-     (SparseGraph->ordered-graphs sparse-graph 20))
+   (SparseGraph->ordered-graphs sparse-graph 20))
   ([sparse-graph max-sweeps]
-     (let [layers (:layers sparse-graph)
-           first-sparse-layer (first layers)
-           last-layer-idx (dec (count layers))]
-       (loop [orderings []
-              ;; seed the first layer with initial ordered layer
-              first-layer (map->OrderedLayer
-                           (-> first-sparse-layer
-                               (dissoc :nodes)
-                               (assoc :items (:nodes first-sparse-layer))))
-              first-layers #{}]
-         (let [c (count orderings)]
-           ;; Graph orderings are determined by the first layer. If we've seen this
-           ;; first layer before, then we can be sure that we're about to enter
-           ;; a cycle, and can thus short circuit
-           (if (or (= c max-sweeps) (contains? first-layers first-layer))
-             orderings
-             (let [reverse? (odd? c)
-                   graph (-> (if reverse?
-                               (rev sparse-graph)
-                               sparse-graph)
-                             (SparseGraph->OrderedGraph first-layer))
-                   backward-graph (if reverse?
-                                    graph
-                                    (rev graph))
-                   ;; This is sort of ugly, but once we order the nodes, we
-                   ;; still have to come up with a good subnode ordering.
-                   ;; Conceptually, this belongs in SparseGraph->OrderedGraph,
-                   ;; but it's also conceptually cromulent to have
-                   ;; SparseGraph->OrderedGraph know nothing about the forward/
-                   ;; reverse dance that we do here. However, subnode ordering
-                   ;; is dependent on direction. My choice then, is to make
-                   ;; SparseGraph->OrderedGraph direction-aware, or pull the
-                   ;; subnode ordering out and put it here, where we're aware
-                   ;; of the direction. For now, I've chosen the latter.
-                   backward-subnode-pass (order-subnodes backward-graph)
-                   forward-subnode-pass (order-subnodes
-                                         (rev backward-subnode-pass))
-                   ords (conj orderings forward-subnode-pass)
-                   layers (:layers graph)]
-               ;; The last layer of the current ordering is the first layer
-               ;; of the next
-               (recur ords (layers last-layer-idx) (conj first-layers first-layer)))))))))
+   (let [layers (:layers sparse-graph)
+         first-sparse-layer (first layers)
+         last-layer-idx (dec (count layers))]
+     (loop [orderings []
+            ;; seed the first layer with initial ordered layer
+            first-layer (map->OrderedLayer
+                         (-> first-sparse-layer
+                             (dissoc :nodes)
+                             (assoc :items (:nodes first-sparse-layer))))
+            first-layers #{}]
+       (let [c (count orderings)]
+         ;; Graph orderings are determined by the first layer. If we've seen this
+         ;; first layer before, then we can be sure that we're about to enter
+         ;; a cycle, and can thus short circuit
+         (if (or (= c max-sweeps) (contains? first-layers first-layer))
+           orderings
+           (let [reverse? (odd? c)
+                 graph (-> (if reverse?
+                             (rev sparse-graph)
+                             sparse-graph)
+                           (SparseGraph->OrderedGraph first-layer))
+                 backward-graph (if reverse?
+                                  graph
+                                  (rev graph))
+                 ;; This is sort of ugly, but once we order the nodes, we
+                 ;; still have to come up with a good subnode ordering.
+                 ;; Conceptually, this belongs in SparseGraph->OrderedGraph,
+                 ;; but it's also conceptually cromulent to have
+                 ;; SparseGraph->OrderedGraph know nothing about the forward/
+                 ;; reverse dance that we do here. However, subnode ordering
+                 ;; is dependent on direction. My choice then, is to make
+                 ;; SparseGraph->OrderedGraph direction-aware, or pull the
+                 ;; subnode ordering out and put it here, where we're aware
+                 ;; of the direction. For now, I've chosen the latter.
+                 backward-subnode-pass (order-subnodes backward-graph)
+                 forward-subnode-pass (order-subnodes
+                                       (rev backward-subnode-pass))
+                 ords (conj orderings forward-subnode-pass)
+                 layers (:layers graph)]
+             ;; The last layer of the current ordering is the first layer
+             ;; of the next
+             (recur ords (layers last-layer-idx) (conj first-layers first-layer)))))))))

 (defn OrderedGraph->CountedAndMarkedGraph
@@ -699,8 +699,8 @@
                                      minus-ps minus-qs)
                                 (apply map vector))]
     (map->CountedAndMarkedGraph (assoc ordered-graph
-                                      :crossings (reduce + crossings)
-                                      :marked (reduce set/union marked)))))
+                                  :crossings (reduce + crossings)
+                                  :marked (reduce set/union marked)))))

 (defn best-ordering


commit id on mouseclick

commit id on mouseclick

--- src/cljs/signet/core.cljs
+++ src/cljs/signet/core.cljs
@@ -69,7 +69,8 @@
                     (append "div")
                     (style {:position "absolute"
                             :z-index 10
-                            :visibility "visisble"}))]
+                            :visibility "hidden"
+                            :color "black"}))]
     (do
       (.. svg
           (selectAll "link")
@@ -93,17 +94,11 @@
                                 "red"
                                 "steelblue"))
                  :r circle-size})
-          (on "mouseover" (fn [d] (do (.. tooltip
-                                         (style {:visiblity "visible"
-                                                 :top (str (- (get y-positions d) 10) "px")
-                                                 :left (str  (+ (get x-positions d) 50)  "px")
-                                                 })
-                                         (text d)))))
-          (on "mouseout" (fn [d] (.. tooltip
-                                    (style {:visiblity "hidden"})
-                                    (text ""))))
-          #_(append "svg:title") #_(text (fn [d] d))
-          ))))
+          (on "click" (fn [d] (do (.. tooltip
+                                     (style {:top (str (- (get y-positions d) 15) "px")
+                                             :left (str  (+ (get x-positions d) 50)  "px")
+                                             :visibility "visible"})
+                                     (text d)))))))))

 (defn commit-graph-view


Debug.

Debug.

--- src/onyx/coordinator/log/datomic.clj
+++ src/onyx/coordinator/log/datomic.clj
@@ -60,7 +60,7 @@
   (let [query '[:find ?task :in $ ?job ?task :where
                 [?job :job/task ?task]
                 [?peer :peer/task ?task]]]
-    (into #{} (mapcat #(first (d/q query db (:db/id %))) job-id tasks))))
+    (into #{} (mapcat #(first (d/q query db job-id (:db/id %))) tasks))))

 (defn sort-tasks-by-phase [db tasks]
   (sort-by :task/phase (map (fn [[t]] (d/entity db t)) tasks)))
@@ -90,9 +90,11 @@
        (first)))

 (defn job-candidate-seq [job-seq last-offered]
-  (->> (cycle job-seq)
-       (drop (inc (.indexOf job-seq last-offered)))
-       (take (count job-seq))))
+  (if (nil? last-offered)
+    job-seq
+    (->> (cycle job-seq)
+         (drop (inc (.indexOf job-seq last-offered)))
+         (take (count job-seq)))))

 (defmethod extensions/mark-peer-born Datomic
   [log place]
@@ -116,8 +118,8 @@
   (let [db (d/db (:conn log))
         job-seq (job-candidate-seq (all-active-jobs-ids db)
                                    (last-offered-job db))
-        candidates (map (partial next-essential-task db) job-seq)]
-    (first (filter identity candidates))))
+        candidates (mapcat (partial next-essential-task db) job-seq)]
+    (filter identity candidates)))

 (defn select-nodes [ent]
   (select-keys ent [:node/peer :node/payload :node/ack


Revert acking code - fixes still required.

--- src/onyx/messaging/acking_daemon.clj
+++ src/onyx/messaging/acking_daemon.clj
@@ -2,7 +2,6 @@
     (:require [clojure.core.async :refer [chan >!! close! sliding-buffer]]
               [com.stuartsierra.component :as component]
               [onyx.static.default-vals :refer [defaults]]
-              [onyx.types :refer [->Ack]]
               [taoensso.timbre :as timbre]))

 (defrecord AckingDaemon [opts]
@@ -25,19 +24,18 @@
 (defn ack-message [daemon message-id completion-id ack-val]
   (let [rets
         (swap!
-          (:ack-state daemon)
-          (fn [state]
-            (if-let [ack (get state message-id)]
-              (let [updated-ack-val (bit-xor (:ack-val ack) ack-val)]
-                (if (zero? updated-ack-val)
-                  (dissoc state message-id)
-                  (assoc state message-id (assoc ack :ack-val updated-ack-val))))
-              (if (zero? ack-val)
-                state
-                (assoc state message-id (->Ack nil completion-id ack-val))))))]
-    (when (get rets message-id)
-      (>!! (:completions-ch daemon) {:id message-id
-                                     :peer-id completion-id}))))
+         (:ack-state daemon)
+         (fn [state]
+           (if-let [current-ack-val (get-in state [message-id :ack-val])]
+             (assoc-in state [message-id :ack-val] (bit-xor current-ack-val ack-val))
+             (assoc state message-id {:completion-id completion-id
+                                      :ack-val ack-val}))))]
+
+    (when-let [x (get rets message-id)]
+      (when (zero? (:ack-val x))
+        (swap! (:ack-state daemon) dissoc message-id)
+        (>!! (:completions-ch daemon) {:id message-id
+                                       :peer-id completion-id})))))

 (defn gen-message-id
   "Generates a unique ID for a message - acts as the root id."
@@ -58,5 +56,3 @@
         (persistent! coll)
         (recur (inc n)
                (conj! coll (.nextLong rng)))))))
-
-


removed unnecessary code

removed unnecessary code

--- src/frontend/renderer.cljs
+++ src/frontend/renderer.cljs
@@ -259,11 +259,6 @@

 (defn play-pause-button [data owner]
   (reify
-    om/IDidMount
-    (did-mount [_]
-      (.click (js/$ "#foo")
-        (fn []
-          (println "YOYOYO"))))
     om/IRender
     (render [this]
       (if (:paused? data)


Herp derp

Herp derp

--- src/grimoire/api.clj
+++ src/grimoire/api.clj
@@ -186,12 +186,13 @@
 ;; Interacting with the datastore - writing
 ;;--------------------------------------------------------------------

-;; FIXME: Remove this update when 1.6 drops
+;; FIXME: Remove this update when 1.7 drops
 (defn update
   "λ [{A → B} A (λ [B args*] → C) args*] → {A → C}

   Updates a key in the map by applying f to the value at that key more
   arguments, returning the resulting map."
+
   [map key f & args]
   (assoc map key
          (apply f (get map key) args)))


Add docstring, more checking

Add docstring, more checking

--- src/grimoire/api.clj
+++ src/grimoire/api.clj
@@ -228,9 +228,15 @@

 ;; Interacting with the datastore - writing
 ;;--------------------------------------------------------------------
-(defn write-docs [config thing data]
+(defn write-docs
+  "Writes a map, being documentation data, into the datastore as specified by
+  config at the def denoted by thing."
+
+  [config thing data]
   (let [thing  (ensure-thing thing)
         _      (assert thing)
-        handle (thing->handle config :docs thing)]
+        _      (assert (isa? :def thing))
+        handle (thing->handle config :docs thing)
+        _      (assert handle)]
     (->> handle io/writer (json/generate-stream data) (.flush))
     nil))


Function keep-word? working great

Function keep-word? working great

--- src/hangman/core.clj
+++ src/hangman/core.clj
@@ -160,7 +160,7 @@
     (main all-words) )
   ( [game-words]
     (do-tests)
-    (let [tgt-word      "uniformed"
+    (let [tgt-word      "comaker"
           words-map     (group-by count game-words)  ; map keyed by word length
           word-list     (words-map (count tgt-word)) ; words of correct length
       ]


fix incorrect arg in bubbles synth (thanks to new arg checker)

--- src/overtone/inst/synth.clj
+++ src/overtone/inst/synth.clj
@@ -343,7 +343,7 @@
         glis (+ bub (* 24 (lf-saw:kr 0.4 0)))
         freq (midicps glis)
         src (* 0.04 (sin-osc freq))
-        zout (comb-n src :decaytime 4)]
+        zout (comb-n src :decay-time 4)]
     zout))

 ; // Originally from the STK instrument models...


Ensure stop-player and kill-player use the player-pool.

--- src/overtone/music/time.clj
+++ src/overtone/music/time.clj
@@ -42,11 +42,12 @@

 (defn stop-player
   "Stop scheduled fn gracefully if it hasn't already executed."
-  [sched-fn] (at-at/stop sched-fn))
+  [sched-fn] (at-at/stop sched-fn :pool player-pool))

 (defn kill-player
-  "Kills scheduled fn immediately if it hasn't already executed."
-  [sched-fn] (at-at/kill sched-fn))
+  "Kills scheduled fn immediately if it hasn't already executed. You
+  are also able to specify player by job id - see print-schedule."
+  [sched-fn] (at-at/kill sched-fn :pool player-pool))

 (def ^{:dynamic true} *apply-ahead*
   "Amount of time apply-at is scheduled to execute *before* it was scheduled


whoops don't make the in-memory db MULTI_THREADED, that's an experimental H2 feature :sweat:

--- src/metabase/db.clj
+++ src/metabase/db.clj
@@ -21,7 +21,7 @@
   ;; see http://h2database.com/html/features.html for explanation of options
   (if (config/config-bool :mb-db-in-memory)
     ;; In-memory (i.e. test) DB
-    "mem:metabase;DB_CLOSE_DELAY=-1;MULTI_THREADED=TRUE"
+    "mem:metabase;DB_CLOSE_DELAY=-1"
     ;; File-based DB
     (let [db-file-name (config/config-str :mb-db-file)
           db-file      (clojure.java.io/file db-file-name)


Temporarily fix issue with requesting secure (https) sites

InfoQ does not support HTTPS for the main presentation site due to CSS, scripts, etc.

Change-Id: Ia26d0671773d0691c70ee43e47a9fd1e48bd0abd

--- src/qcast/infoq/scraper.clj
+++ src/qcast/infoq/scraper.clj
@@ -2,7 +2,7 @@
   (:gen-class)
   (:require [clj-time.coerce  :as time-coerce]
             [clj-time.format  :as time]
-            [clojure.string   :refer [split trim]]
+            [clojure.string   :refer [replace-first split trim]]
             [qcast.cache      :as cache]
             [qcast.html       :refer :all]
             [qcast.infoq.site :as infoq]
@@ -126,7 +126,8 @@
   (let [md-keys [:id :link :poster :keywords :summary :title :authors
                  :record-date :publish-date :online-date
                  :length :pdf :audio :video :slides :times]
-        md-vals (juxt (constantly id) (constantly (infoq/presentation-url id))
+        allow-insecure #(replace-first % #"^https://" "http://")
+        md-vals (juxt (constantly id) (constantly (allow-insecure (infoq/presentation-url id)))
                       poster keywords summary title authors
                       record-date publish-date online-date
                       length pdf audio video slides times)]


Load deployment workflows in core/deploy.

--- src/incise/deploy/core.clj
+++ src/incise/deploy/core.clj
@@ -1,5 +1,6 @@
 (ns incise.deploy.core
-  (:require [incise.config :as conf])
+  (:require (incise [config :as conf]
+                    [load :refer [load-deployment-workflows]]))
   (:refer-clojure :exclude [get]))

 (defonce workflows (atom {}))
@@ -11,6 +12,7 @@
   "Deploy using the user's specified workflow."
   [& {:as config}]
   (conf/merge config)
+  (load-deployment-workflows)
   (let [{workflow-name :workflow :as settings} (conf/get :deploy)
         workflow (get workflow-name)]
     (if workflow


all good

all good


close clone dialog on success (#497)

close clone dialog on success (#497)

--- src/cljs/org/broadinstitute/firecloud_ui/page/workspace/summary/workspace_cloner.cljs
+++ src/cljs/org/broadinstitute/firecloud_ui/page/workspace/summary/workspace_cloner.cljs
@@ -81,5 +81,5 @@
             :on-done (fn [{:keys [success? get-parsed-response]}]
                        (swap! state dissoc :working?)
                        (if success?
-                         ((:on-success props) project name)
+                         (do (modal/pop-modal) ((:on-success props) project name))
                          (swap! state assoc :error (get-parsed-response))))}))))})


adjusting to new ct-id

adjusting to new ct-id

--- test/celestial/test/proxmox.clj
+++ test/celestial/test/proxmox.clj
@@ -16,7 +16,7 @@

 (with-conf
   (let [{:keys [machine proxmox]} redis-prox-spec]
-    (with-redefs [ct-id (fn [_] nil)]
+    (with-redefs [ct-id (fn [_] (fn [_] nil))]
       (fact "missing vmid"
             (vconstruct (assoc-in redis-prox-spec [:proxmox :vmid] nil)) =>
             (throws ExceptionInfo (with-m? {:machine {:vmid '("vmid must be present")}} ))))


Add tests for the slash-redirect :add case

--- test/cljc/reitit/ring_test.cljc
+++ test/cljc/reitit/ring_test.cljc
@@ -238,6 +238,31 @@
         (testing "endpoint with top-level handler"
           (is (= response (app {:request-method :get, :uri "/any"})))
           (is (= response (app {:request-method :options, :uri "/any"}))))))))
+
+(deftest trailing-slash-handler-test
+  (testing "using :method :add"
+    (let [ok {:status 200 :body "ok"}
+          app (ring/ring-handler
+                (ring/router
+                  [["/slash-less" {:get (constantly ok),
+                                   :post (constantly ok)}]
+                   ["/with-slash/" {:get (constantly ok),
+                                    :post (constantly ok)}]])
+                (ring/redirect-trailing-slash-handler {:method :add}))]
+
+      (testing "exact matches work"
+        (is (= ok (app {:request-method :get, :uri "/slash-less"})))
+        (is (= ok (app {:request-method :post, :uri "/slash-less"})))
+        (is (= ok (app {:request-method :get, :uri "/with-slash/"})))
+        (is (= ok (app {:request-method :post, :uri "/with-slash/"}))))
+
+      (testing "adds slashes"
+        (is (= 301 (:status (app {:request-method :get, :uri "/with-slash"}))))
+        (is (= 308 (:status (app {:request-method :post, :uri "/with-slash"})))))
+
+      (testing "does not strip slashes"
+        (is (= nil (app {:request-method :get, :uri "/slash-less/"})))
+        (is (= nil (app {:request-method :post, :uri "/slash-less/"})))))))

 (deftest async-ring-test
   (let [promise #(let [value (atom ::nil)]


Better assertion for grouping test.

Better assertion for grouping test.

--- test/workshop/jobs/test_2_3.clj
+++ test/workshop/jobs/test_2_3.clj
@@ -58,18 +58,24 @@

 (deftest test-level-2-challenge-3
   (try
-    (let [catalog (c/build-catalog)
-          lifecycles (c/build-lifecycles)]
-      (user/go (u/n-peers catalog c/workflow))
-      (u/bind-inputs! lifecycles {:read-segments input})
-      (let [peer-config (u/load-peer-config (:onyx-id user/system))
-            job {:workflow c/workflow
-                 :catalog catalog
-                 :lifecycles lifecycles
-                 :task-scheduler :onyx.task-scheduler/balanced}]
-        (onyx.api/submit-job peer-config job)
-        (let [[results] (u/collect-outputs! lifecycles [:write-segments])]
-          (u/segments-equal? expected-output results))))
+    (let [results
+          (with-out-str
+            (let [catalog (c/build-catalog)
+                  lifecycles (c/build-lifecycles)]
+              (user/go (u/n-peers catalog c/workflow))
+              (u/bind-inputs! lifecycles {:read-segments input})
+              (let [peer-config (u/load-peer-config (:onyx-id user/system))
+                    job {:workflow c/workflow
+                         :catalog catalog
+                         :lifecycles lifecycles
+                         :task-scheduler :onyx.task-scheduler/balanced}]
+                (onyx.api/submit-job peer-config job)
+                (let [[results] (u/collect-outputs! lifecycles [:write-segments])]
+                  (u/segments-equal? expected-output results)))))
+          lines (butlast (rest (clojure.string/split results #"\n")))
+          groups (group-by #(last (re-find #":user-id (\d+).*" %)) lines)]
+      (doseq [k (keys groups)]
+        (is (apply = (map #(last (re-find #"Peer (\w+-\w+-\w+-\w+-\w+).*" %)) (get groups k))))))
     (catch InterruptedException e
       (Thread/interrupted))
     (finally


more tests for YB.core.chat (#201)

more tests for YB.core.chat (#201)

* more tests for chat

* tests for send-msg-for-each

--- test/yetibot/core/test/chat.clj
+++ test/yetibot/core/test/chat.clj
@@ -1,5 +1,5 @@
 (ns yetibot.core.test.chat
-  (:require [midje.sweet :refer [facts fact =>]]
+  (:require [midje.sweet :refer [facts fact => =not=> provided as-checker]]
             [clojure.string :as s]
             [yetibot.core.chat :as c]))

@@ -27,8 +27,81 @@
  "about should-send-msg-for-each?"
  (fact
   "it will return 'true' when you pass it a legit chat data stucture and
-   a formatted message that has \newlines and URLs that contain image like
+   a formatted message that has :newlines and URLs that contain image like
    chars"
   (let [data ["look at my picture"
               "http://image.jpg"]]
     (c/should-send-msg-for-each? data (s/join \newline data)) => true)))
+
+(facts
+ "about suppressed-pred"
+ (fact
+  "it will get an object's :suppressed metadata and return it's value"
+  (let [truthy (c/suppress {})
+        falsey {}]
+    (c/suppressed-pred truthy) => true
+    (c/suppressed-pred falsey) =not=> true)))
+
+(facts
+ "about suppressed?"
+ (fact
+  "it will check to see if an obj, or collection of objects passed in are
+   considered suppressed, and return a boolean result"
+  (let [truthy (c/suppress {})
+        falsey {}
+        truthycoll [truthy truthy]
+        mixedcoll [truthy falsey]
+        falseycoll [falsey falsey]]
+    (c/suppressed? truthy) => true
+
+    ;; why is the below test returning true ??
+    ;; i get that it is a coll?, but the item in the coll does NOT
+    ;; contain a :suppress metadata item eql to true, so what gives ??
+    ;; (c/suppressed? falsey) =not=> true
+
+    (c/suppressed? truthycoll) => true
+    (c/suppressed? mixedcoll) =not=> true
+    (c/suppressed? falseycoll) =not=> true)))
+
+(facts
+ "about suppress"
+ (fact
+  "it attaches a metadata :supress keyword equal to true to whatever obj is
+  provided"
+  (let [truthy (c/suppress {})]
+    (:suppress (meta truthy)) => true)))
+
+(facts
+ "about with-target"
+ (fact
+  "it attaches a metadata :target keyword equal to whatever value is provided
+   to the obj (data-structure) that is provided"
+  (let [target "i am the target"
+        ds (c/with-target target {})]
+    (:target (meta ds)) => target)))
+
+(facts
+ "about channels-with-broadcast"
+ (fact
+  "it will return a collection of only those channels that have a broadcast
+   settings value equal to true"
+  (count (c/channels-with-broadcast)) => 1
+  (provided (c/all-channels) => [[nil nil nil]
+                                 [nil nil {"broadcast" "true"}]
+                                 [nil nil {"broadcast" "false"}]])))
+
+(facts
+ "about send-msg-for-each"
+ (fact
+  "it will send a message for each item in the msg collection, assuming it
+   is less than the max allowable"
+  (c/send-msg-for-each [1]) => nil
+  (provided (c/send-msg 1) => :didsend))
+
+ (fact
+  "it will only send the max number of allowed messages in a single batch, plus
+   one to let user know messsage batch was truncated"
+  (c/send-msg-for-each (range 40)) => :sent-msg
+  (provided
+   (c/send-msg (as-checker int?)) => :sent-msg :times c/max-msg-count
+   (c/send-msg (as-checker string?)) => :sent-msg :times 1)))


remove build focus for css

remove build focus for css

--- sidecar/src/figwheel_sidecar/auto_builder.clj
+++ sidecar/src/figwheel_sidecar/auto_builder.clj
@@ -85,8 +85,7 @@
    {:builds  builds
     :builder (builder figwheel-server)
     :each-iteration-hook (fn [_ build]
-                           (fig/check-for-css-changes
-                            (merge-build-into-server-state figwheel-server build)))}))
+                           (fig/check-for-css-changes figwheel-server))}))

 (defn check-autobuild-config [all-builds build-ids figwheel-server]
   (let [builds (config/narrow-builds* all-builds build-ids)]


Escape dots in CORS pattern.

Escape dots in CORS pattern.

--- src/cavm/core.clj
+++ src/cavm/core.clj
@@ -60,8 +60,8 @@
 ; XXX might want to disable http from xenabrowser.net, but currently we don't have
 ; certs on dev & beta.
 (def trusted-hosts
-  ["https?://([-_A-Za-z0-9]+.)?xenabrowser.net(:[0-9]+)?"
-   "https://genome-cancer.ucsc.edu"])
+  ["https?://([-_A-Za-z0-9]+\\.)?xenabrowser\\.net(:[0-9]+)?"
+   "https://genome-cancer\\.ucsc\\.edu"])

 (def local-trusted-host "http://localhost(:[0-9]+)?")


added frameworkMessage callback for executor

--- src/riak_mesos/executor.clj
+++ src/riak_mesos/executor.clj
@@ -1,26 +1,20 @@
 (ns riak-mesos.executor
   (:require
-            [clj-mesos.executor :as exec])
+   [clj-mesos.executor :as exec]
+   clojure.java.shell)
   (:gen-class))
-
-;; (def riak-scheduler (sch/scheduler
-;;                      (resourceOffers [driver offers]
-;;                                       (let [[offer] offers]
-;;                                         (sch/launch-tasks driver (:offer-id offer)
-;;                                                          [{:name "riak-task"
-;;                                                            :task-id "riak-01"
-;;                                                            :slave-id (:slave-id offer)
-;;                                                            :resources {:cpus 1.0
-;;                                                                        :mem 100.0}
-;;                                                            :command {:value "sleep 10"}}])))))

 (defn riak-executor []
   (exec/executor (registered [driver executor framework slave]
                                               (println "Framework Registered"))
-                                  (launchTask [driver task-info]
-                                              (exec/send-status-update driver {:task-id (:task-id task-info)
-                                                                               :task-state 1
-                                                                               :message "Riak Task is running" } ))))
+                 (launchTask [driver task-info]
+                             (println "[launchTask] Sending status Update")
+                             (exec/send-status-update driver {:task-id (:task-id task-info)
+                                                              :task-state 1
+                                                              :message "Riak Task is running" } ))
+                 (frameworkMessage [driver bytes] (let [command-string (read-string (String. bytes "UTF-8"))]
+                                                    (println "[frameworkMessage] Running command " command-string )
+                                                    (future (apply clojure.java.shell/sh  command-string ))))))


Add some fade test cues.

Add some fade test cues.

--- src/afterglow/examples.clj
+++ src/afterglow/examples.clj
@@ -435,6 +435,27 @@
                            :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
                            :color :yellow))

+    (ct/set-cue!
+     (:cue-grid *show*) 5 7
+     (cues/cue :fade-test (fn [var-map]
+                            (fx/fade "Fade Test"
+                                     (fx/blank)
+                                     (global-color-effect :blue :include-color-wheels? true)
+                                     (params/bind-keyword-param (:phase var-map 0) Number 0)))
+               :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
+               :color :cyan))
+
+(ct/set-cue!
+ (:cue-grid *show*) 6 7
+ (cues/cue :fade-test-2 (fn [var-map]
+                          (fx/fade "Fade Test 2"
+                                   (move/direction-effect "p/t" (params/build-pan-tilt-param :pan 0 :tilt 0)
+                                                          (show/fixtures-named "torrent"))
+                                   (move/direction-effect "p/t" (params/build-pan-tilt-param :pan 0 :tilt 0)
+                                                          (show/fixtures-named "blade"))
+                                   (params/bind-keyword-param (:phase var-map 0) Number 0)))
+           :variables [{:key "phase" :min 0.0 :max 1.0 :start 0.0 :name "Fade"}]
+           :color :red))

     (ct/set-cue! (:cue-grid *show*) 7 7
                  (cues/function-cue :strobe-all :strobe (show/all-fixtures) :effect-name "Raw Strobe"))


Remove half-written cue.

Remove half-written cue.

--- src/afterglow/examples.clj
+++ src/afterglow/examples.clj
@@ -705,8 +705,6 @@
                                         :min -20.0 :max 20.0 :start 0.0 :centered true :resolution 0.05}
                                        {:key "y" :name "Y"
                                         :min 0.0 :max 20.0 :start 0.0 :centered false :resolution 0.05}]))
-    (ct/set-cue! (cue-grid *show) 3 8
-                 (cues/cue :blade-speed (fn [_])))
     (ct/set-cue! (:cue-grid *show*) 3 8
                  (cues/function-cue :blade-speed :movement-speed (show/fixtures-named "blade")
                                     :color :purple :effect-name "Slow Blades"))


Deal with out of sync clocks between client and server in dealing with relative time description. Minor cljs code cleanup.

--- src/posthere/cljs/posthere.cljs
+++ src/posthere/cljs/posthere.cljs
@@ -5,10 +5,7 @@
                 [clojure.string :as s]
                 [hiccups.runtime :as hiccupsrt]))

-; index page
-(defn- update-uuid-value
-    [selector]
-    (.text ($ "#urlUUIDInputDisplay") (.val ($ selector))))
+;; ----- Unique UUID generation -----

 (defn- uuid
   "
@@ -34,6 +31,10 @@
   "
   (s/join "-" (take 3 (rest (s/split (uuid) #"-")))))

+(defn- update-uuid-value
+    [selector]
+    (.text ($ "#urlUUIDInputDisplay") (.val ($ selector))))
+
 (defn- set-base-uuid []
   "Generate and set a base UUID view for our page"
   (def base_uuid (short-uuid))
@@ -44,6 +45,8 @@
     [selector]
     (.text ($ "#urlMethodInputDisplay") (.val ($ selector))))

+;; ----- Data manipulation functions for presented results -----
+
 (defn- html-escape
   "Make a string possibly containing HTML display literally rather than as intepreted HTML."
   [string]
@@ -52,9 +55,17 @@
 (defn- time-ago
   "Use the momemnt.js library to return a human readable English string describing how long ago the request was made."
   [result]
-  (.fromNow (js/moment. (aget result "timestamp"))))
+  (let [timestamp (aget result "timestamp")
+        relative-time (.fromNow (js/moment. timestamp))]
+    ;; Relative times in the future make no sense for our case.
+    ;; It just mean clocks are out of sync between our server
+    ;; and the user's browser. Change future relative times, marked
+    ;; by the presence of "from", to "just now".
+    (if (re-find #"from" relative-time)
+      "just now"
+      relative-time)))

-;; ----- Result Table Building Functions -----
+;; ----- Result table building functions -----

 (defn- table-header [label]
   [:tr [:th.text-center {:colspan 2} label]])


fn documentation

fn documentation

--- src/pretty/cli/ansi_escapes.clj
+++ src/pretty/cli/ansi_escapes.clj
@@ -1,127 +1,127 @@
 (ns pretty.cli.ansi-escapes)
-;TODO fn docs
-(def esc-code "Returns the escape code" "\033[")
-(def reset-code "Returns the code to reset all attributes" (str esc-code "0m"))
+
+(def esc-code "Return the string of basic escape code" "\033[")
+(def reset-code "Return the string code to reset all attributes" (str esc-code "0m"))

 (defn cursor-to
-  "Move the cursor to the 'x, y' cell"
+  "Return the string code to move the cursor to the 'x, y' cell"
   ([] (str esc-code "H"))
   ([x] (str esc-code (+ x 1) "G"))
   ([x y] (str esc-code (+ y 1) ";" (+ x 1) "H")))

 (defn cursor-move
-  "Move the cursor by 'x' and 'y' cells"
+  "Return the string code to move the cursor by 'x' and 'y' cells"
   [x y]
   (let [x-code (if (< x 0) (str (- x) "D") (str x "C"))
         y-code (if (< y 0) (str (- y) "A") (str y "B"))]
     (str esc-code x-code esc-code y-code)))

 (defn cursor-up
-  "Moves the cursor 'n' (default 1) cells up"
+  "Return the string code to move the cursor 'n' (default 1) cells up"
   ([n] (str esc-code n "A"))
   ([] (cursor-up 1)))

 (defn cursor-down
-  "Moves the cursor 'n' (default 1) cells down"
+  "Return the string code to move the cursor 'n' (default 1) cells down"
   ([n] (str esc-code n "B"))
   ([] (cursor-down 1)))

 (defn cursor-forward
-  "Moves the cursor 'n' (default 1) cells forward"
+  "Return the string code to move the cursor 'n' (default 1) cells forward"
   ([n] (str esc-code n "C"))
   ([] (cursor-forward 1)))

 (defn cursor-backward
-  "Moves the cursor 'n' (default 1) cells backward"
+  "Return the string code to move the cursor 'n' (default 1) cells backward"
   ([n] (str esc-code n "D"))
   ([] (cursor-backward 1)))

 (defn cursor-left
-  "Moves the cursor to the left"
+  "Return the string code to move the cursor to the left"
   []
   (str esc-code "G"))

 (defn cursor-position
-  "Retrieve the cursor position"
+  "Return the string code to retrieve the cursor position"
   []
   (str esc-code "6n"))

 (defn cursor-position-save
-  "Save the cursor position"
+  "Return the string code to save the cursor position"
   []
   (str esc-code "s"))

 (defn cursor-position-restore
-  "Restore the cursor position"
+  "Return the string code to restore the cursor position"
   []
   (str esc-code "u"))

 (defn cursor-next-line
-  "Moves the cursor to beginning of the next line"
+  "Return the string code to move the cursor to beginning of the next line"
   []
   (str esc-code "E"))

 (defn cursor-prev-line
-  "Moves the cursor to beginning of the previous line"
+  "Return the string code to move the cursor to beginning of the previous line"
   []
   (str esc-code "F"))

 (defn cursor-hide
-  "Hide the cursor"
+  "Return the string code to hide the cursor"
   []
   (str esc-code "?25l"))

 (defn cursor-show
-  "Show the cursor"
+  "Return the string code to show the cursor"
   []
   (str esc-code "?25h"))

 (defn erase-end-line
-  "Erase to the end of the line"
+  "Return the string code to erase to the end of the line"
   []
   (str esc-code "K"))

 (defn erase-start-line
-  "Erase to the start of the line"
+  "Return the string code to erase to the start of the line"
   []
   (str esc-code "1K"))

 (defn erase-line
-  "Erase the line"
+  "Return the string code to erase the line"
   []
   (str esc-code "2K"))

 (defn erase-down
-  "Erase down"
+  "Return the string code to erase down"
   []
   (str esc-code "J"))

 (defn erase-up
-  "Erase up"
+  "Return the string code to erase up"
   []
   (str esc-code "1J"))

 (defn erase-screen
-  "Erase the screen"
+  "Return the string code to erase the screen"
   []
   (str esc-code "2J"))

 (defn scroll-up
-  "Scroll screen up"
+  "Return the string code to scroll screen up"
   []
   (str esc-code "S"))

 (defn scroll-down
-  "Scroll screen down"
+  "Return the string code to scroll screen down"
   []
   (str esc-code "T"))

 (defn clear-screen
-  "Clear screen"
+  "Return the string code to clear screen"
   []
   (str "\u001Bc"))

 (defn beep
-  "Emit a beep"
+  "Return the string code to emit a beep"
   []
-  (str "\u0007"))
+  (str "\0007"))


[#3081] Refactor try-apply-operation-2

[#3081] Refactor try-apply-operation-2

to be able to reuse logic inside undo-2

--- backend/src/akvo/lumen/lib/transformation/engine.clj
+++ backend/src/akvo/lumen/lib/transformation/engine.clj
@@ -160,75 +160,109 @@
     (throw (ex-info "Failed to transform. Transformation can't have columns from more than one data-group specified"
                     {:transformation transformation}))))

-(defn execute-transformation-2
-  [{:keys [tenant-conn] :as deps} dataset-id job-execution-id transformation]
-  (let [dataset-version (db.dataset-version/latest-dataset-version-2-by-dataset-id tenant-conn {:dataset-id dataset-id})
-        data-groups (db.data-group/list-data-groups-by-dataset-version-id tenant-conn {:dataset-version-id (:id dataset-version)})
-        columns-in-transformation (columns-used (w/keywordize-keys transformation) (reduce into [] (map :columns data-groups)))
+(defn try-apply-operation-2
+  "adapt try-apply-operation to work with data-groups:
+  1. find data-group related to transformation
+  2. grab all data-group columns
+  3. apply-operation
+  4. separate transformation data-group columns from the others"
+  [{:keys [tenant-conn dataset-id claims] :as deps}
+   {:keys [dataset-version transformation data-groups]}]
+  (let [columns-in-transformation (columns-used (w/keywordize-keys transformation) (reduce into [] (map :columns data-groups)))
         _  (ensure-one-data-group-related transformation columns-in-transformation data-groups)
         column-name (first columns-in-transformation)
         data-group (datagroup-by-column data-groups column-name)
         source-table (:table-name data-group)
         other-dgs-columns (db.data-group/get-all-columns-except-group-id tenant-conn {:dataset-version-id (:id dataset-version)
-                                                                                :group-id (:group-id data-group)})
-        previous-columns (into (vec (:columns data-group)) other-dgs-columns)]
-    (let [{:keys [success? message columns execution-log error-data data-groups-to-be-created]}
-          (try-apply-operation deps source-table previous-columns (assoc transformation :dataset-id dataset-id))
-          columns (let [other-dgs-columns-set (set other-dgs-columns)]
-                    (reduce (fn [container column]
-                              (if (contains? other-dgs-columns-set column)
-                                container
-                                (conj container column))) [] columns))]
-      (when-not success?
-        (log/errorf "Failed to transform: %s, columns: %s, execution-log: %s, data: %s" message columns execution-log error-data)
-        (throw (ex-info (or message "") {})))
-      (let [new-dataset-version-id (str (util/squuid))]
-        (let [next-dataset-version {:id new-dataset-version-id
-                                    :dataset-id dataset-id
-                                    :job-execution-id job-execution-id
-                                    :version (inc (:version dataset-version))
-                                    :author (:claims deps)
-                                    :transformations (w/keywordize-keys
-                                                      (conj (vec (:transformations dataset-version))
-                                                            (assoc transformation
-                                                                   "created" (Instant/ofEpochMilli (System/currentTimeMillis))
-                                                                   "changedColumns" (diff-columns previous-columns
-                                                                                columns))))}
-
-              ]
-          (db.dataset-version/new-dataset-version-2 tenant-conn next-dataset-version)
-          (when data-groups-to-be-created
-            (let [max-group-order (apply max (conj (map :group-order data-groups) 1000))
-                  adapted-data-groups (map-indexed (fn [i item]
-                                                     (let [idx (inc (+ i max-group-order))
-                                                           group-name (str (:group-name item) " [merge]")]
-                                                       (-> item
-                                                           (assoc :group-order idx)
-                                                           (assoc :group-id idx)
-                                                           (assoc :group-name group-name)
-                                                           (update :columns (fn [cols]
-                                                                              (mapv #(assoc % "groupId" idx "groupName" group-name) cols))))))
-                                                   data-groups-to-be-created)]
-              (doseq [dg adapted-data-groups]
-                     (db.data-group/new-data-group tenant-conn
-                                                   (merge
-                                                    dg
-                                                    {:id (util/squuid)
-                                                     :dataset-version-id new-dataset-version-id})))))
+                                                                                :group-id (:group-id data-group)})
+        previous-columns (into (vec (:columns data-group)) other-dgs-columns)
+        {:keys [success? message execution-log error-data data-groups-to-be-created] :as res}
+        (try-apply-operation deps source-table previous-columns (assoc transformation :dataset-id dataset-id))
+        columns (let [other-dgs-columns-set (set other-dgs-columns)]
+                  (reduce (fn [container column]
+                            (if (contains? other-dgs-columns-set column)
+                              container
+                              (conj container column))) [] (:columns res)))]
+    (when-not success?
+      (log/errorf "Failed to transform: %s, columns: %s, execution-log: %s, data: %s" message columns execution-log error-data)
+      (throw (ex-info (or message "") {})))
+    {:data-groups-to-be-created data-groups-to-be-created
+     :columns columns
+     :previous-columns previous-columns
+     :data-group data-group}))
+
+(defn post-try-apply-operation-2
+  "
+  1. create dataset-version(-2) with new transformation in transformations
+  2. create new data-groups if tx result need it. eg: merge-datasets
+  3. create new data-group with new columns related to the tx
+  4. create all other data-groups to point new dataset-version-id
+  5. touch dataset
+  "
+  [{:keys [tenant-conn claims dataset-id] :as deps}
+   {:keys [job-execution-id transformation dataset-version data-groups]}
+   {:keys [previous-columns columns data-groups-to-be-created data-group]}]
+  (let [new-dataset-version-id (str (util/squuid))]
+    (db.dataset-version/new-dataset-version-2 tenant-conn {:id               new-dataset-version-id
+                                                           :dataset-id       dataset-id
+                                                           :job-execution-id job-execution-id
+                                                           :version          (inc (:version dataset-version))
+                                                           :author           claims
+                                                           :transformations  (w/keywordize-keys
+                                                                              (conj (vec (:transformations dataset-version))
+                                                                                (assoc transformation
+                                                                                "created" (Instant/ofEpochMilli (System/currentTimeMillis))
+                                                                                "changedColumns" (diff-columns previous-columns
+                                                                                columns))))})
+    (when data-groups-to-be-created
+      (let [max-group-order     (apply max (conj (map :group-order data-groups) 1000))
+            adapted-data-groups (map-indexed (fn [i item]
+                                               (let [idx        (inc (+ i max-group-order))
+                                                     group-name (str (:group-name item) " [merge]")]
+                                                 (-> item
+                                                     (assoc :group-order idx)
+                                                     (assoc :group-id idx)
+                                                     (assoc :group-name group-name)
+                                                     (update :columns (fn [cols]
+                                                                        (mapv #(assoc % "groupId" idx "groupName" group-name) cols))))))
+                                             data-groups-to-be-created)]
+        (doseq [dg adapted-data-groups]
           (db.data-group/new-data-group tenant-conn
                                         (merge
-                                         (select-keys data-group
-                                                      [:imported-table-name :table-name :group-id :group-name :repeatable :group-order])
-                                         {:id (util/squuid)
-                                          :dataset-version-id new-dataset-version-id
-                                          :columns columns}))
-          (doseq [dg (db.data-group/list-data-groups-by-dataset-version-id tenant-conn
-                                                                                {:dataset-version-id (:id dataset-version)})
-                  :when (not= (:id dg) (:id data-group))]
-            (db.data-group/new-data-group tenant-conn (-> dg
-                                                          (assoc :dataset-version-id new-dataset-version-id :id (util/squuid))
-                                                          (update :columns vec))))
-          (db.transformation/touch-dataset tenant-conn {:id dataset-id}))))))
+                                         dg
+                                         {:id                 (util/squuid)
+                                          :dataset-version-id new-dataset-version-id})))))
+    (db.data-group/new-data-group tenant-conn
+                                  (merge
+                                   (select-keys data-group
+                                                [:imported-table-name :table-name :group-id :group-name :repeatable :group-order])
+                                   {:id                 (util/squuid)
+                                    :dataset-version-id new-dataset-version-id
+                                    :columns            columns}))
+    (doseq [dg    (db.data-group/list-data-groups-by-dataset-version-id tenant-conn
+                                                                        {:dataset-version-id (:id dataset-version)})
+            :when (not= (:id dg) (:id data-group))]
+      (db.data-group/new-data-group tenant-conn (-> dg
+                                                    (assoc :dataset-version-id new-dataset-version-id :id (util/squuid))
+                                                    (update :columns vec))))
+    (db.transformation/touch-dataset tenant-conn {:id dataset-id})))
+
+(defn execute-transformation-2
+  [{:keys [tenant-conn claims] :as deps} dataset-id job-execution-id transformation]
+  (let [dataset-version (db.dataset-version/latest-dataset-version-2-by-dataset-id tenant-conn {:dataset-id dataset-id})
+        data-groups (db.data-group/list-data-groups-by-dataset-version-id tenant-conn {:dataset-version-id (:id dataset-version)})
+        deps (assoc deps :dataset-id dataset-id)
+        tx-data {:data-groups data-groups
+                 :dataset-version dataset-version
+                 :job-execution-id job-execution-id
+                 :transformation transformation}
+        {:keys [columns previous-columns data-groups-to-be-created data-group]}
+        (try-apply-operation-2 deps tx-data)]
+    (post-try-apply-operation-2 deps tx-data
+                                {:columns columns
+                                 :previous-columns previous-columns
+                                 :data-group data-group
+                                 :data-groups-to-be-created data-groups-to-be-created})))

 (defn execute-transformation-1
   [{:keys [tenant-conn] :as deps} dataset-id job-execution-id transformation]