แฒกแแแแแ แงแแแแแก. แแแแแแแแแ แกแขแแขแแแก แแแแ แแแฌแแแแก แแแ แแแแแก, แ แแแแแแช แกแแแชแแแแฃแ แแ แแแแแแแแแฃแแแ แแฃแ แกแแก แกแขแฃแแแแขแแแแกแแแแก.
Apache Beam แแ DataFlow แ แแแแฃแ แแ แแจแ แแแแกแแแแแแแแกแแแแก
Google Cloud-แแก แแแงแแแแแ
แจแแแแจแแแ: แแ แแแแแแแงแแแ Google Cloud Shell แแแแกแแแแแแก แแแกแแจแแแแแ แแ แแแ แแแแฃแแ แแฃแ แแแแแก แแแแแชแแแแแแก แแแแแฅแแแงแแแแแก แแแแ, แ แแแแแ แแแญแแ แแ แแแแกแแแแแแก แแแจแแแแ Python 3-แจแ. Google Cloud Shell แแงแแแแแก Python 2-แก, แ แแแแแแช แฃแคแ แ แจแแแกแแแแแแแ Apache Beam-แก.
แแแแกแแแแแแก แแแกแแฌแงแแแแ, แฉแแแ แชแแขแ แฃแแแ แฉแแแฃแฆแ แแแแแแ แแแ แแแแขแ แแแก. แแแแแแแก, แแแกแแช แแฅแแแแ แแ แแแแแฃแงแแแแแแ GCP, แแแแแฌแแแ แแแแชแแแก แฅแแแแแ แแแชแแแฃแแ 6 แแแแแฏแ
แแแแก แจแแแแแ, แฉแแแ แฃแแแ แแแขแแแ แแแ แฉแแแแ แกแแ แแแขแแแ Google Cloud Storage-แจแ แแ แแแแแแแแ แแ แแกแแแ แฉแแแแก Google Cloud Shel-แจแ. แฆแ แฃแแแแแแ แกแแชแแแจแ แแขแแแ แแแ แกแแแแแแ แขแ แแแแแแฃแ แแ (แแฆแฌแแ แแแแแ แจแแแแซแแแแ แแแฎแแ
แคแแแฃแ แ 2
แแ แซแแแแแแแ, แ แแแแแแแช แแแญแแ แแแแ แคแแแแแแแก แแแแแ แแแแกแแแแก แแ แกแแญแแ แ แแแแแแแแแแแแแก แแแกแแงแแแแแแแ, แฅแแแแแ แแแชแแแฃแแแ.
# Copy file from cloud storage
gsutil cp gs://<YOUR-BUCKET>/ * .
sudo pip install apache-beam[gcp] oauth2client==3.0.0
sudo pip install -U pip
sudo pip install Faker==1.0.2
# Environment variables
BUCKET=<YOUR-BUCKET>
PROJECT=<YOUR-PROJECT>
แฉแแแแ แแแแแชแแแแ แแแแแก แแ แชแฎแ แแแแก แจแแฅแแแ
แแแก แจแแแแแ แ แแช แแแแแกแ แฃแแแแ แแแงแแแแแแก แงแแแแ แกแแคแแฎแฃแ แก, แจแแแแแแ แ แแช แฃแแแ แแแแแแแแแ แแ แแก แแแแแชแแแแ แแ แชแฎแ แแแแก แจแแฅแแแ BigQuery-แจแ. แแแแก แแแแแแแแแก แ แแแแแแแแ แแแ แแ แกแแแแแก, แแแแ แแ แฃแแแ แขแแแแกแ แแ แแก Google Cloud แแแแกแแแแก แแแแแงแแแแแ, แแแ แแแแแ แแแแแชแแแแ แแแแ แแแแก แจแแฅแแแแ. แจแแแแซแแแแ แแแฐแงแแแ แฅแแแแแ แแแชแแแฃแ แแแแแฏแแแก
แกแฃแ แแแ 3. แแแแแแแก แแแแแแแแแ
แแแแฎแแแ แแแแแก แแฃแ แแแแแก แแแแแชแแแแแแก แแแแแฅแแแงแแแแ
Pub/Sub แแ แแก แฉแแแแ แแแแกแแแแแแก แแแแจแแแแแแแแแ แแแแแแแแแขแ, แ แแแแแ แแก แกแแจแฃแแแแแแก แแซแแแแก แแ แแแแ แแแแแฃแแแแแแแ แแแแแแแชแแแก แแแฃแแแแจแแ แแแแ แแ แแแแแแแก. แแแ แซแแ, แแก แแฃแจแแแแก แ แแแแ แช แจแฃแแแแแแแ, แ แแแแแแช แกแแจแฃแแแแแแก แแแแซแแแแก แแแแแแแแแแแ แแ แแแแแฆแแ แจแแขแงแแแแแแแแแ แแแแแแแชแแแแก แจแแ แแก. แแแ แแแแ แ แแช แฃแแแ แแแแแแแแแ แแ แแก แแแแแก แจแแฅแแแ. แฃแแ แแแแ แแแแแแแ Pub/Sub-แแ แแแแกแแแจแ แแ แแแแญแแ แแ CREATE TOPIC.
แฅแแแแแ แแแชแแแฃแแ แแแแ แแแฃแฌแแแแแก แฉแแแแก แกแแ แแแขแก, แ แแ แจแแฅแแแแก แแแแแ แแแแกแแแฆแแ แฃแแ แแฃแ แแแแแก แแแแแชแแแแแ แแ แจแแแแแ แแแแแจแแ แแแก แแ แแแแแแแแก แแฃแ แแแแแแก Pub/Sub-แจแ. แแ แแแแแ แแ แ แแช แฃแแแ แแแแแแแแแ แแ แแก แแแแแฅแขแแก แจแแฅแแแ PublisherClient, แแแแแแแก แแแแแงแแแแแแ แแแฃแแแแแ แแแแแกแแแ แแแแแแแแ แแแ topic_path
แแ แแแแแแซแแฎแแ แคแฃแแฅแชแแ publish
ั topic_path
แแ แแแแแชแแแแแ. แแแฎแแแ แแแแแแแแแกแฌแแแแ, แ แแ แฉแแแ แแแแแ แขแก generate_log_line
แฉแแแแ แกแชแแแแ แแแแ stream_logs
, แแแแขแแ แแแ แฌแแฃแแแแ, แ แแ แแก แคแแแแแแ แแแแแ แกแแฅแแฆแแแแแจแแ, แฌแแแแแฆแแแแ แจแแแแฎแแแแแจแ แแฅแแแ แแแแฆแแแ แแแแแ แขแแก แจแแชแแแแแก. แแแแก แจแแแแแ แฉแแแ แจแแแแแซแแแ แแแแแขแแ แแ แแก แฉแแแแ Google แแแแกแแแแก แแแจแแแแแแ:
python publish.py
from stream_logs import generate_log_line
import logging
from google.cloud import pubsub_v1
import random
import time
PROJECT_ID="user-logs-237110"
TOPIC = "userlogs"
publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path(PROJECT_ID, TOPIC)
def publish(publisher, topic, message):
data = message.encode('utf-8')
return publisher.publish(topic_path, data = data)
def callback(message_future):
# When timeout is unspecified, the exception method waits indefinitely.
if message_future.exception(timeout=30):
print('Publishing message on {} threw an Exception {}.'.format(
topic_name, message_future.exception()))
else:
print(message_future.result())
if __name__ == '__main__':
while True:
line = generate_log_line()
print(line)
message_future = publish(publisher, topic_path, line)
message_future.add_done_callback(callback)
sleep_time = random.choice(range(1, 3, 1))
time.sleep(sleep_time)
แ แแแแ แช แแ แคแแแแ แแแแจแแแแ, แฉแแแ แจแแแซแแแแ แแแแแแแฎแแ แแฃแ แแแแแก แแแแแชแแแแแแก แแแแแแแแแแ แแแแกแแแจแ, แ แแแแ แช แแก แแแฉแแแแแแแ แฅแแแแแ แแแชแแแฃแ แคแแแฃแ แแจแ. แแก แกแแ แแแขแ แแแฃแจแแแแแก แแแแแ, แกแแแแ แฉแแแ แแ แแแงแแแแแ CTRL + Cแแแก แแแกแแกแ แฃแแแแแแ.
แกแฃแ แแแ 4. แแแแแแแแแแ publish_logs.py
แฉแแแแ แแแแกแแแแแแก แแแแแก แแแฌแแ แ
แแฎแแ, แ แแแแกแแช แงแแแแแคแแ แ แแแแแแแแแฃแแ แแแแฅแแก, แจแแแแแซแแแ แแแแแฌแงแแ แกแแฎแแแแกแ แแแฌแแแ - แฉแแแแ แแแแกแแแแแแก แแแแแ แแแ Beam-แแกแ แแ Python-แแก แแแแแงแแแแแแ. Beam แแแแกแแแแแแก แจแแกแแฅแแแแแแ, แฉแแแ แฃแแแ แจแแแฅแแแแ แแแแกแแแแแแก แแแแแฅแขแ (p). แแแก แจแแแแแ แ แแช แจแแแฅแแแแ แแแแกแแแแแแก แแแแแฅแขแก, แฉแแแ แจแแแแแซแแแ แแแแแแแงแแแแ แ แแแแแแแแ แคแฃแแฅแชแแ แแ แแแแแแแแก แแแงแแแแแแ แแแแ แแขแแ แแก แแแแแงแแแแแแ pipe (|)
. แแแแแแแ, แกแแแฃแจแแ แแ แแชแแกแ แฐแแแแก แฅแแแแแ แแแชแแแฃแ แกแฃแ แแแก.
[Final Output PCollection] = ([Initial Input PCollection] | [First Transform]
| [Second Transform]
| [Third Transform])
แฉแแแแก แแแแจแ แฉแแแ แจแแแฅแแแแ แแ แแแ แแแแฃแ แคแฃแแฅแชแแแก. แคแฃแแฅแชแแ regex_clean
, แ แแแแแแช แกแแแแแ แแแก แแแแแชแแแแแก แแ แแฆแแแก แจแแกแแแแแแก แแฌแแ แแแก PATTERNS แกแแแก แกแแคแฃแซแแแแแ แคแฃแแฅแชแแแก แแแแแงแแแแแแ re.search
. แคแฃแแฅแชแแ แแแ แฃแแแแก แแซแแแแ แแแแแงแแคแแแ แกแขแ แแฅแแแก. แแฃ แแฅแแแ แแ แฎแแ แ แ แแแฃแแแ แฃแแ แแแแแฎแแขแแแก แแฅแกแแแ แขแ, แแแ แฉแแแ แจแแแแแฌแแแ แแก datetime
แคแฃแแฅแชแแแก แจแแแแแ, แ แแแ แแก แแแฃแจแแแก. แแแแแ แขแแก แจแแชแแแแแก แแแฆแแแแ แคแแแแแก แแแกแแฌแงแแกแจแ, แ แแช แฃแชแแแฃแ แ แแงแ. แแก แกแแ แจแแแแแ แแแแแแชแแแ แคแฃแแฅแชแแแก WriteToBigQuery, แ แแแแแแช แฃแแ แแแแ แแแแขแแแก แฉแแแแก แแแแแชแแแแแก แชแฎแ แแแจแ. Batch DataFlow Job-แแกแ แแ Streaming DataFlow Job-แแก แแแแ แแแชแแแฃแแแ แฅแแแแแ. แแ แแแแแ แแ แแแแกแฎแแแแแแ แกแแ แแฃแ แแ แกแขแ แแแแแ แแแแก แจแแ แแก แแ แแก แแก, แ แแ แแแ แขแแแจแ แแแแแฎแฃแแแแ CSV-แก src_path
แคแฃแแฅแชแแแก แแแแแงแแแแแแ ReadFromText
แกแฎแแแแแแ.
Batch DataFlow Job (แกแแแแคแ แแแแฃแจแแแแแ)
import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions
from google.cloud import bigquery
import re
import logging
import sys
PROJECT='user-logs-237110'
schema = 'remote_addr:STRING, timelocal:STRING, request_type:STRING, status:STRING, body_bytes_sent:STRING, http_referer:STRING, http_user_agent:STRING'
src_path = "user_log_fileC.txt"
def regex_clean(data):
PATTERNS = [r'(^S+.[S+.]+S+)s',r'(?<=[).+?(?=])',
r'"(S+)s(S+)s*(S*)"',r's(d+)s',r"(?<=[).d+(?=])",
r'"[A-Z][a-z]+', r'"(http|https)://[a-z]+.[a-z]+.[a-z]+']
result = []
for match in PATTERNS:
try:
reg_match = re.search(match, data).group()
if reg_match:
result.append(reg_match)
else:
result.append(" ")
except:
print("There was an error with the regex search")
result = [x.strip() for x in result]
result = [x.replace('"', "") for x in result]
res = ','.join(result)
return res
class Split(beam.DoFn):
def process(self, element):
from datetime import datetime
element = element.split(",")
d = datetime.strptime(element[1], "%d/%b/%Y:%H:%M:%S")
date_string = d.strftime("%Y-%m-%d %H:%M:%S")
return [{
'remote_addr': element[0],
'timelocal': date_string,
'request_type': element[2],
'status': element[3],
'body_bytes_sent': element[4],
'http_referer': element[5],
'http_user_agent': element[6]
}]
def main():
p = beam.Pipeline(options=PipelineOptions())
(p
| 'ReadData' >> beam.io.textio.ReadFromText(src_path)
| "clean address" >> beam.Map(regex_clean)
| 'ParseCSV' >> beam.ParDo(Split())
| 'WriteToBigQuery' >> beam.io.WriteToBigQuery('{0}:userlogs.logdata'.format(PROJECT), schema=schema,
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND)
)
p.run()
if __name__ == '__main__':
logger = logging.getLogger().setLevel(logging.INFO)
main()
แแแแแชแแแแ แแแแแแแก แกแแแฃแจแแ (แแแแแแแก แแแแฃแจแแแแแ)
from apache_beam.options.pipeline_options import PipelineOptions
from google.cloud import pubsub_v1
from google.cloud import bigquery
import apache_beam as beam
import logging
import argparse
import sys
import re
PROJECT="user-logs-237110"
schema = 'remote_addr:STRING, timelocal:STRING, request_type:STRING, status:STRING, body_bytes_sent:STRING, http_referer:STRING, http_user_agent:STRING'
TOPIC = "projects/user-logs-237110/topics/userlogs"
def regex_clean(data):
PATTERNS = [r'(^S+.[S+.]+S+)s',r'(?<=[).+?(?=])',
r'"(S+)s(S+)s*(S*)"',r's(d+)s',r"(?<=[).d+(?=])",
r'"[A-Z][a-z]+', r'"(http|https)://[a-z]+.[a-z]+.[a-z]+']
result = []
for match in PATTERNS:
try:
reg_match = re.search(match, data).group()
if reg_match:
result.append(reg_match)
else:
result.append(" ")
except:
print("There was an error with the regex search")
result = [x.strip() for x in result]
result = [x.replace('"', "") for x in result]
res = ','.join(result)
return res
class Split(beam.DoFn):
def process(self, element):
from datetime import datetime
element = element.split(",")
d = datetime.strptime(element[1], "%d/%b/%Y:%H:%M:%S")
date_string = d.strftime("%Y-%m-%d %H:%M:%S")
return [{
'remote_addr': element[0],
'timelocal': date_string,
'request_type': element[2],
'body_bytes_sent': element[3],
'status': element[4],
'http_referer': element[5],
'http_user_agent': element[6]
}]
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument("--input_topic")
parser.add_argument("--output")
known_args = parser.parse_known_args(argv)
p = beam.Pipeline(options=PipelineOptions())
(p
| 'ReadData' >> beam.io.ReadFromPubSub(topic=TOPIC).with_output_types(bytes)
| "Decode" >> beam.Map(lambda x: x.decode('utf-8'))
| "Clean Data" >> beam.Map(regex_clean)
| 'ParseCSV' >> beam.ParDo(Split())
| 'WriteToBigQuery' >> beam.io.WriteToBigQuery('{0}:userlogs.logdata'.format(PROJECT), schema=schema,
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND)
)
result = p.run()
result.wait_until_finish()
if __name__ == '__main__':
logger = logging.getLogger().setLevel(logging.INFO)
main()
แแแแแแแแ แแก แแแจแแแแ
แฉแแแ แจแแแแแซแแแ แแแแแขแแ แแ แแแแกแแแแแ แกแฎแแแแแกแฎแแ แแแแ. แแฃ แแแแแแแแ, แจแแแแแซแแ แแแกแ แแแจแแแแ แแแแแแแแ แแแแ แขแแ แแแแแแแแแ GCP-แจแ แแแกแขแแแชแแฃแ แแ แจแแกแแแแกแแก.
python -m main_pipeline_stream.py
--input_topic "projects/user-logs-237110/topics/userlogs"
--streaming
แแฃแแชแ, แฉแแแ แแแแแ แแแ แแแก แแแจแแแแแก DataFlow-แแก แแแแแงแแแแแแ. แฉแแแ แจแแแแแซแแแ แแแแก แแแแแแแแ แฅแแแแแ แแแชแแแฃแแ แแ แซแแแแแแก แแแแแงแแแแแแ แจแแแแแแ แกแแญแแ แ แแแ แแแแขแ แแแแก แแแงแแแแแแ.
project
โ แแฅแแแแ GCP แแ แแแฅแขแแก ID.runner
แแ แแก แแแแกแแแแแแก แแแแจแแแแ, แ แแแแแแช แแแแแแแแแแแก แแฅแแแแก แแ แแแ แแแแก แแ แแแจแแแแแก แแฅแแแแก แแแแกแแแแแก. แฆแ แฃแแแแจแ แแแกแแจแแแแแ, แแฅแแแ แฃแแแ แแแฃแแแแแ DataflowRunner.staging_location
โ แแแ Cloud Dataflow แฆแ แฃแแแแแแ แกแแชแแแจแ, แกแแแฃแจแแแก แจแแแกแ แฃแแแแแแ แแ แแชแแกแแ แแแแกแแแแก แกแแญแแ แ แแแแแก แแแแแขแแแแก แแแแแฅแกแแชแแแกแแแแก.temp_location
โ แแแ Cloud Dataflow แฆแ แฃแแแแแแแ แกแแชแแแแกแแแ แแแแกแแแแแแก แแฃแจแแแแแก แแ แแก แจแแฅแแแแแ แกแแแฃแจแแแแแแก แแ แแแแแแ แคแแแแแแแก แจแแกแแแแฎแแ.streaming
python main_pipeline_stream.py
--runner DataFlow
--project $PROJECT
--temp_location $BUCKET/tmp
--staging_location $BUCKET/staging
--streaming
แกแแแแ แแก แแ แซแแแแแ แแฃแจแแแแก, แฉแแแ แจแแแแแซแแแ แแแแแแแแแ DataFlow แฉแแแแ แแแ google แแแแกแแแจแ แแ แแแแฎแแ แฉแแแแ แแแแกแแแแแ. แ แแแแกแแช แฉแแแ แแแฌแแแแฃแแแแ แแแแกแแแแแแ, แฉแแแ แฃแแแ แแแแแแแฎแแ แแกแแแแกแ แ แแ, แ แแช แแแฎแแข 4-แก. แแแแแ แแแแก แแแแแแแแกแแแแก, แจแแแซแแแแ แซแแแแแ แกแแกแแ แแแแแ แแงแแก Logs-แแ แแแแแกแแแ แแ แจแแแแแ Stackdriver-แแ แแแขแแแฃแ แ แแฃแ แแแแแแแก แกแแแแฎแแแแ. แแก แแแแแฎแแแ แ แแแแกแแแแแแก แกแแแแแฎแแแแก แแแแแญแ แแจแ แ แแ แจแแแแฎแแแแแแจแ.
แกแฃแ แแแ 4: แกแฎแแแแก แแแแแแแแ แ
แฉแแแแก แแแแแชแแแแแแ แฌแแแแแ BigQuery-แจแ
แแกแ แ แแ, แฉแแแ แฃแแแ แฃแแแ แแแฅแแแแแก แแแแกแแแแแ, แ แแแแแแช แแฃแจแแแแก แฉแแแแก แชแฎแ แแแจแ แแแแแชแแแแแแ. แแแแก แจแแกแแแแฌแแแแแแ แจแแแแแซแแแ แแแแแแแแแ BigQuery-แแ แแ แจแแแฎแแแแ แแแแแชแแแแแก. แฅแแแแแ แแแชแแแฃแแ แแ แซแแแแแแก แแแแแงแแแแแแก แจแแแแแ, แแฅแแแ แฃแแแ แแแฎแแ แแแแแชแแแแ แแแแ แแแแก แแแ แแแแ แ แแแแแแแแ แกแขแ แแฅแแแ. แแฎแแ, แ แแแแกแแช แฉแแแ แแแแฅแแก BigQuery-แจแ แจแแแแฎแฃแแ แแแแแชแแแแแ, แจแแแแแซแแแ แฉแแแแขแแ แแ แจแแแแแแแ แแแแแแแ, แแกแแแ แแแแแแแแ แแ แแแแแชแแแแแ แแแแแแแแแแ แแ แแแแแฌแงแแ แแแแแแก แแแแฎแแแแแ แแแกแฃแฎแแก แแแชแแแ.
SELECT * FROM `user-logs-237110.userlogs.logdata` LIMIT 10;
แกแฃแ แแแ 5: BigQuery
แแแกแแแแ
แแแแแแแแแแแ, แ แแ แแก แแแกแขแ แแฅแแแแ แกแแกแแ แแแแแ แแแแแแแแ แแแแแแแก แแแแแชแแแแ แแแแกแแแแแแก แจแแกแแฅแแแแแแ, แแกแแแ แแแแแชแแแแ แฃแคแ แ แฎแแแแแกแแฌแแแแแแแแก แแแกแแฃแแฏแแแแกแแแแแ. แแแแแชแแแแ แแ แคแแ แแแขแจแ แจแแแแฎแแ แแแแ แฃแแแ แแขแแกแแแแก แแแแซแแแแก. แแฎแแ แฉแแแ แจแแแแแซแแแ แแแแแฌแงแแ แแแกแฃแฎแแก แแแชแแแ แแแแจแแแแแแแแ แแแแฎแแแแแ, แ แแแแ แแชแแ แ แแแแแแ แแแแแแแแ แแงแแแแแก แฉแแแแก แแ แแแฃแฅแขแก? แแแ แแแแ แแฅแแแแ แแแแฎแแแ แแแแแก แแแแ แแ แแแ แแแแแแแแแแแจแ? แแ แแแฃแฅแขแแก แ แแแแ แแกแแแฅแขแแแแแ แฃแ แแแแ แแแแแ แแแแแแแแแแ แงแแแแแแ แแแขแแ? แแ แแ แแก แจแแชแแแแแแ แกแแแแช แแ แฃแแแ แแงแแก? แแก แแก แแแแฎแแแแแ, แ แแแแแแแช แแ แแแแแแแชแแแกแแแแก แกแแแแขแแ แแกแ แแฅแแแแ. แแ แแแแฎแแแแแ แแแกแฃแฎแแแแแแ แแแฆแแแฃแแ แจแแฎแแแฃแแแแแแแก แกแแคแฃแซแแแแแ, แฉแแแ แจแแแแแซแแแ แแแแแฃแแฏแแแแกแแ แแ แแแฃแฅแขแ แแ แแแแแแ แแแ แแแแฎแแแ แแแแแก แฉแแ แแฃแแแแ.
Beam แแแ แแแแช แกแแกแแ แแแแแแ แแ แขแแแแก แแแ แฏแแจแแกแแแแก แแ แแฅแแก แกแฎแแ แกแแแแขแแ แแกแ แแแแแงแแแแแแก แจแแแแฎแแแแแแแช. แแแแแแแแแ, แจแแแซแแแแ แแกแฃแ แ แ แแแแฃแ แแ แแจแ แแแแแแแแแแแ แกแแคแแแแ แขแแแแแแแก แแแแแชแแแแแ แแ แแแแแแแแ แแแญแ แแแ แแแแแแแแก แกแแคแฃแซแแแแแ, แจแแกแแซแแแ, แแฅแแแ แแแฅแแ แกแแแกแแ แแก แแแแแชแแแแแ, แ แแแแแแแช แแแแแก แแแแฅแแแแแแแแ แแ แแกแฃแ แ แแแแแแแแแแ แขแ แแคแแแแก แแแแแก แแแแแแแแแแ. แแฅแแแ แแกแแแ แจแแแซแแแแ แแงแแ, แแแแแแแแแ, แกแแแแแแจแ แแแแแแแแ, แ แแแแแแช แแแ แแแแแก แแแแฎแแแ แแแแแก แแแแแชแแแแแก แแ แแงแแแแแก แแแก แกแแแแคแแ แแแชแแ แแแคแแแแก แจแแกแแฅแแแแแแ แซแแ แแแแแ แแแขแ แแแแก แแแแแงแฃแ แแก แแแแแแแแกแแแแก. แแแ แแ, แแแขแแแแแ, แแก แแ แแก แแแแแ แแ แแ แแแกแขแแก แแแแ, แแแแแแแแ, แ แแ แแแแฎแฃแแแแ, แฎแแแ แแแกแแช แกแฃแ แก แกแ แฃแแ แแแแแก แแแฎแแ, แฅแแแแแ แแ แแก แฉแแแ GitHub-แแก แแแฃแแ.
แแก แงแแแแแคแแ แ.
แฌแงแแ แ: www.habr.com