Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Archive for the ‘Павутина’ Category

Як швидко розпочати писати SPA на AngularJS (1)

leave a comment »

Тому що чим швидше ми зробимо щось що зможемо помацати поклацати – тим менше сили волі буде треба для підтримки мотивації. (Так, я знаю що писати таку публікацію два роки – то задовго, але краще пізно ніж ніколи. Сподіваюсь що хоча б тому хто буде підтримувати проекти на Angular 1 (а я не впевнений що їх багато мігрує на новіші версії) це знадобиться).

Варто мати встановленим NodeJS. Він має менеджер пакетів npm. І з його допомогою ми скачаємо всі необхідні бібліотеки. Ми ж перестали шукати софт на сайтах ще коли почали користуватись менеджерами пакетів в Linux, те ж саме ми робимо коли нам треба бібліотека для python, то чим розробка для браузерів гірша?

Тут я був написав кілька абзаців про те як за допомогою npm поставити bower (інший менеджер пакетів), але це трохи збочення, бо npm нас може й сам задовольнити. Тому поки що обійдемось. Let the hacking begin.

Створюємо порожню директорію для нашого проекту, і в ній виконуємо:

npm init

Прочитати решту цього запису »

Written by bunyk

1 Червня, 2017 at 14:01

Опубліковано в Кодерство, Павутина

Tagged with ,

Як написати бота до Telegram?

with 5 comments

Легко. 🙂 Давайте напишемо бота який перекладатиме нам всяке з німецької:

Приклад діалогу

Для цього нам треба поговорити з botFather-ом:

А зараз трохи не по темі цієї статті. Ось код який перетворює вікідані на словник, шукаючи всі сутності які мають мітки однією мовою, а потім показучи їх мітки іншою мовою, використовуючи хитрий запит SPARQL:

import json
import requests

def translate(from_lang, to_lang, word):
    '''
        Переклдає мітки елементів вікіданих з мови на мову. Повертає список варіантів перекладу
    '''
    res = sparql('''
        SELECT  ?ukLabel WHERE {
          ?item ?label "%s"@%s.
          ?item rdfs:label ?ukLabel filter(lang(?ukLabel) = "%s")
        } LIMIT 10
    ''' % (word, from_lang, to_lang))
    return list(map(
        lambda e: e['ukLabel']['value'],
        res['results']['bindings']
    ))

def sparql(query):
    ''' Отримує JSON дані запиту SPARQL до вікіданих '''
    res = requests.get(
        'https://query.wikidata.org/sparql',
        params={
            'query': query,
            'format': 'json'
        }
    )
    return json.loads(res.text)

А тепер повертаємось до теми телеграмного бота. Аби його написати треба поставити бібліотеку:

pip install pyTelegramBotAPI

Ось її Github: https://github.com/eternnoir/pyTelegramBotAPI

А далі – елементарно як писати консольну програму:

import telebot

TOKEN = '' # тут вставити те що BotFather сказав

bot = telebot.TeleBot(TOKEN)

@bot.message_handler(content_types=["text"]) # Якщо прийдуть нові повідомлення
def respond_to_message(message):
    translations = translate('de', 'uk', message.text) # Отримати переклади тексту повідомленя
    resp = '\n'.join(translations) if translations else 'На жаль, перекладу слова %s не знайдено' % message.text
    bot.send_message( # відправити назад
        message.chat.id, # в той самий чат з якого прийшло (можна напевне й в інший)
        resp
    )

if __name__ == '__main__':
     bot.polling(none_stop=True) # Запустити бота аби той сидів на лінії і слухав повідомлення.

Поки що все, бо й висипатись іноді треба. Пізніше нагадайте мені не забути написати більше про SPARQL, як поставити собі локальну mediawiki і розширення до неї, як логінити сторонні застосунки через OAuth, і як переписати інтерфейс вікіпедії на Vue.js. 🙂

Written by bunyk

22 Травня, 2017 at 01:51

Опубліковано в Кодерство, Павутина

Tagged with ,

Конспект Vue.js

with 6 comments

Не варто припиняти вчити щось нове, правда? І писати – надійніший метод запам’ятати ніж просто читати, тому спробую повернути блог до життя.

CDN

Найпростіший спосіб яким ви можете почати використовувати Vue – це завантажити його на свою сторінку з CDN: https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js

Hello world!

Якщо у нас є такий HTML шаблон:

<div id="app">
  {{title}}
</div>

То мінімальний JavaScript який дозволяє його заповнити виглядає так:

var data = { // Модель - це просто будь-який об'єкт
    title: "Hello world!"
};
new Vue({
  el: "#app", // вибрати елемент за id
  data: data  // приєднати модель
});

Тепер, якщо в консолі браузера написати:

data.title = 'It works!'

То текст на сторінці зміниться автоматично. (І не треба ніякої мороки з дайджест-циклом через angular.element(e).scope().$apply() (Ангуляр-страждання, забийте)).

От так в’ю оновлюється коли змінюється модель. Як користувач може змінити модель?
Прочитати решту цього запису »

Written by bunyk

26 Квітня, 2017 at 22:37

Опубліковано в Кодерство, Павутина

Tagged with

Побудова “скриньок з вусами” львівських квартир що здаються на сьогодні

with 3 comments

Я ще минулого року помітив що в питаннях про Python на StackOverflow обговорюють якісь панди. Це, як виявилось обгортка навколо matplotlib, numpy і подібних гарних речей. А ще, лазячи по своїх документах в Google знайшов скачану вже позаминулого року стіну групи пошуку нерухомості вконтакті. І так співпало що я і мій колега-аналітик зараз шукаємо квартиру у Львові. Я йому показав цей файл, і він загорівся бажанням проаналізувати ще якийсь сайт оголошень.

При всій повазі до lun.ua, але тут я прорекламую dom.ria.com. Передовсім, там є українська версія. А ще, можливість скачати результати пошуку як електронну таблицю, хоч і в xls форматі, і лише одну сторінку.

В python читати xls вміє бібліотека xlrd, тому треба доставити ще й її. Pandas взагалі має багато необов’язкових залежностей:

sudo pip3.5 install jupyter pandas xlrd matplotlib
jupyter notebook # дуже модний графічний інтерпретатор

Якщо все поставити як вище і запустити “jupyter”, то можна робити обчислення в отакому документі: https://github.com/bunyk/mypandas/blob/master/dom.ria/dom.ria.ipynb
Прочитати решту цього запису »

Written by bunyk

4 Січня, 2017 at 01:30

Зміни моделі, події і чистота функцій в Elm

with one comment

Ця публікація містить ретельно закоментовану альтернативу TodoMVC на Elm. Правда щоб зрозуміти все одно спершу варто прочитати приклади Elm на вікіпедії і основи архітектури Elm програм (вона подібна до Redux якщо ви знаєте що це слово означає (бо я не знаю)).


<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Main</title>
<script type="text/javascript" src="lifelog.js"></script>
</head>
<body>
<script type="text/javascript">
var data = localStorage.lifelog;
var lifelog = Elm.LifeLog.fullscreen(
(data || null) && JSON.parse(data)
);
lifelog.ports.setStorage.subscribe(function(state) {
console.log('saving', state);
localStorage.lifelog = JSON.stringify(state);
});
</script>
</body>
</html>

view raw

index.html

hosted with ❤ by GitHub


Порти можна використовувати лише в порт-модулях, тому ми оголошуємо наш модуль порт-модулем
Таким чином ми не потрапимо в репозиторій пакетів ELm і не забруднимо його
Бруднокровкам заборонено лазити в репозиторії Elm. 🙂
Бруднокровність (те що ми порт) означає що ми спілкуватимемось з JavaScript,
що може викликати непередбачувані побічні ефекти. Чисті модулі в Elm працюють
лише згідно сигнатури.
port module LifeLog exposing (main)
Залежності
import Html exposing (body, h2, text, input, Html, Attribute, button, div, p, b, em)
import Html.App as App
import Html.Attributes exposing (placeholder, value)
import Html.Events exposing (onInput, onClick, on, keyCode)
import Json.Decode as Json
import String exposing (length)
import Time exposing (Time, second)
programWithFlags означає що функція init приймає початкову модель ззовні
Тобто що коли ми скомпілюємо цей модуль і вставимо його в index.html,
ми зможемо запустити його передавши початкові дані:
var lifelog = Elm.LifeLog.fullscreen(initialData)
main =
App.programWithFlags
{ init = init як утворюється початкова модель
, view = view як модель перетворюється на те що бачить користувач
, update = update як модель змінюється у відповідь на різні події
, subscriptions = subscriptions які події окрім тих про які ми самі просимо можуть приходити
}
Вихідний порт
Виклик setStorage з моделлю поверне нам команду, яка викличе підписку на
стороні порта в JavaScript і передасть їй ті дані
lifelog.ports.setStorage.subscribe(function(state) {
localStorage.lifelog = JSON.stringify(state);
});
port setStorage : Model -> Cmd msg
MODEL
type alias LogEntry = { Складений тип "запис щоденника"
timestamp: Time, Час початку події
text: String, Опис події
duration: Time Тривалість події
}
type alias Model = { А це власне всі дані програми
now: Time, Поточний час
currentText: String, Поточний текст в редакторі
log: List LogEntry Список записів щоденника
}
emptyModel: Model Порожній щоденник
emptyModel = {
now = 0,
currentText = "",
log = []
}
Функція init приймає може модель (а може ніщо)
і повертає точно модель і початкову команду
Якщо приймає ніщо – повертає emptyModel, інакше ту модель яку передали
І за замовчуванням порожню команду
init : Maybe Model -> (Model, Cmd Msg)
init savedModel =
(Maybe.withDefault emptyModel savedModel, Cmd.none)
UPDATE
Повідомлення (події) на які програма може реагувати)
type Msg Це алгебраїчний тип (тобто може мати одне з наступних значень):
= Tick Time Оновити час на вказаний
| Edit String Замінити рядок на вказаний
| Submit Зробити новий запис в щоденник
| NoOp нічого не робити
Оновлення моделі
Приймає повідомлення і модель, повертає нову модель і команду для рушія Elm
Командою може бути запит на випадкове число, Http запит, спілкування з портом
і т.п.
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Tick newTime -> Якщо змінився час
(updateTime model newTime, Cmd.none) Оновити час в моделі і нічого не робити
Edit newText -> Якщо змінився текст
({model | currentText = newText}, Cmd.none) Оновити текст і нічого не робити
Submit -> Якщо ми хочемо додати новий запис
updateLog model То повернути нову модель і якісь команди
NoOp -> Якщо ми нічого не хочемо робити
(model, Cmd.none) То повертути ту ж модель і жодних команд
Оновлює модель і повертає команду передати її в порт setStorage
updateLog: Model -> (Model, Cmd Msg)
updateLog model =
let newModel =
{model | log = addEntry model, оновлюємо лог
currentText = "" очищаємо редактор для нового тексту
}
in
(newModel, setStorage newModel)
Додає новий запис до списку записів на основі поточної моделі
addEntry: Model -> List LogEntry
addEntry model =
let
newEntry = { Формуємо новий запис
text = model.currentText,
timestamp = model.now,
duration = 0
}
in
case model.log of
[] -> [newEntry] Якщо щоденник порожній – додати новий запис
Якщо ж вже містить хоч один елемент, то
Додати новий елемент перед ним
потім той що містився в кінці з оновленою тривалістю часу
а потім все решта без змін
le :: log -> newEntry :: updateDuration le model.now :: log
Отримати запис щоденника і поточний час, і оновити тривалість запису
updateDuration: LogEntry -> Time -> LogEntry
updateDuration entry new_time =
Тривалість – це поточний час мінус час початку
{entry | duration = new_time entry.timestamp}
Функція яка бере модель і час, і повертає нову модель
Описує що відбувається якщо змінюється чаc
updateTime: Model -> Time -> Model
updateTime model time =
let
newLog = case model.log of Є два стани щоденника
[] -> [] порожній не змінюється
А в тому який містить хоч елемент змінюється тривалість останнього елемента.
head :: tail -> updateDuration head time :: tail
in
{model |
now = time, оновити поточний час в моделі
log = newLog і стан щоденника
}
SUBSCRIPTIONS
Функція повертає підписки (які повідомлення і в яких випадках Elm має генерувати)
В цьому випадку – щосекунди має приходити повідомлення Tick
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every second Tick
VIEW
Приймаємо модель і повертаємо HTML DOM та повідомлення (події які з того DOM
можуть приходити. Різні елементи можуть різні повідомлення відправляти)
view : Model -> Html Msg
view model =
body [] [ кожен елемент це функція що приймає список атрибутів і список піделементів
h2 [] [ text "Precise life log"],
list2html model.log,
text "It is ",
– f <| g x – це те саме що f (g x) (<| – композиція функцій)
b [] [text <| formatTime model.now],
text " ",
input [
placeholder "What you are doing now?", приклад атрибуту
onInput Edit, приклад посилання повідомлення при події
value model.currentText,
onEnter Submit
] [],
button [onClick Submit] [text "So it goes"]
]
А це так робиться модульність у в'юшці
Приймаємо елемент щоденника, повертаємо частину DOM
item2html: LogEntry -> Html Msg
item2html l =
p [] [
b [] [text <| formatTime l.timestamp]
, text " "
,text l.text
, em [] [text (" Duration: (" ++ (formatTime l.duration) ++ ")")]
]
Приймаємо ввесь щоденник, повертаємо DOM що містить всі записи
list2html: List LogEntry -> Html Msg
list2html list =
div [] (List.map item2html (List.reverse list))
А так ми фільтруємо повідомлення що виходять з в'юшки
onEnter : Msg -> Attribute Msg
onEnter msg =
let
tagger code =
if code == 13 then msg else NoOp
in
on "keydown" (Json.map tagger keyCode)
TIME
TODO: replace with https://github.com/mgold/elm-date-format
getSeconds: Time -> Int
getSeconds time =
(floor <| Time.inSeconds time) % 60
getMinutes: Time -> Int
getMinutes time =
(floor <| Time.inMinutes time) % 60
getHours: Time -> Int
getHours time =
(floor <| Time.inHours time) % 24
addZero: String -> String
addZero s =
if (length s) >= 2 then s else "0" ++ s
formatTime: Time -> String
formatTime time =
(addZero <| toString <| getHours time)
++ ":" ++ (addZero <| toString <| getMinutes time)
++ ":" ++ (addZero <| toString <| getSeconds time)

view raw

lifelog.elm

hosted with ❤ by GitHub


default:
elm-make lifelog.elm –output=lifelog.js

view raw

Makefile

hosted with ❤ by GitHub

Written by bunyk

2 Листопада, 2016 at 01:34

Опубліковано в Кодерство, Павутина

Tagged with ,