ããã«ã¡ã¯ãHabrahabrã®èªè ã®çããïŒ
ãã®ãããã¯ã§ã¯ã4æ¥éã§Telegramçšã®ããããéçºããçµéšãçãããšå ±æããããšæããŸãã ãã®ãããã¯ãåä¿¡ãããã¹ãŠã®é³å£°ã¡ãã»ãŒãžãããã¹ãã«å€æããŸãã ç§ã¯ããã«ãããããããšããŸããããé«å質ã§-ããã€ãã®æè¡ãåŠã³ãŸããã ééããéå£ãå æããããã»ã¹ãå¯èœãªéã詳现ã«èª¬æããŸãã å¿ èŠãªã¹ãã«ããªããŠãã補åãç«ã¡äžããããšã¯ããã»ã©é£ãããªãããšã蚌æããŸãã
ãã®èšäºã¯ãããã°ã©ãã³ã°ã®åå¿è ïŒå®æåã®éªéã«ãªãé害ã®æ°ã確èªããããïŒãšãããé«åºŠãªå°é家ã®äž¡æ¹ã«èå³ããããããããŸããã
åæ
ããã§ã1人ã®ããã°ã©ãã4æ¥éã§äœãã§ããã§ããããïŒ
ã¢ãžã¥ãŒã«ã®äœæãåäžç»é¢iOSã¢ããªã±ãŒã·ã§ã³ã®äœæãTelegramã§ã®15ïŒ è€éãªãããã®äœæãDota2ã§ã®MMRã®äžãäžãããŸãã¯ãªãŒããŒãŠã©ããã§ã®ã©ã³ã¯ä»ãã èªç¶ã®äžã§é±æ«ãéããããããžã ã«è¡ã£ãããããŒã«ã§æ³³ãã ãã顧客ã®å人ã芪relativeãé€ããŠèª°ã䜿çšããªãã¯ã©ã€ã¢ã³ãåãã«500ã1000è¡ã®ã³ãŒããèšè¿°ãããã§ããŸãã æåŸã®ãéã§ã·ãªã³ã³ãã¬ãŒãžã®éãæ©ã¿ã2ã3ã®ãã¬ãçªçµãèŠãŠã1ã2åã®äŒè°ã§å€ãã®äººã ãšç¥ãåããã¢ã»ã³ãã©ãŒã®ããã¥ã¡ã³ãã«è²Œãä»ããŸãã
ããããããããã¹ãŠå®å šãªãã³ã»ã³ã¹ã ãšèšã£ããã©ãã§ããããïŒ ç§ãããªãã«ç§å¯ãåãããªãã°ïŒããã¯ããã»ã©ç°¡åã§ã¯ãããŸããã æéã¯çžå¯Ÿçãªãã®ã§ãããç°ãªãå€ãšä¿æ°ã§æž¬å®ã§ããŸãã ç§ã®ãæ°ã«å ¥ãã®åºæºã¯ãæ©æµãåããæéã®é¢ä¿ã§ãã ããã°ã©ããŒã4æ¥éã§åžå Žã«æ°è£œåãæå ¥ã§ãããšèšã£ããã©ããªãã§ããããïŒ èå³ããããŸããïŒ -èªãã§ãã ããã
ããæ°
æè¿ããç§ãã¡èªèº«ã®IvangaiããTelegramã®ããã°ã©ããŒã³ãã¥ããã£ã«è¿œå ãããé³å£°ã¡ãã»ãŒãžã§å·Šå³ã«æ£ãããããã«ãªããŸããïŒçªç¶ãããŒããŒãã§æã§æžãã®ã¯é£ããããšãç¥ã£ãŠããŸãïŒã åœç¶ã人ã ã¯äŒè©±ã®æ¬è³ªãç解ããããã«1æ¥2ã3æéã¡ãã»ãŒãžãèãããšã«ããããããŠããŸããããããŠã誰ãããã¹ãŠã®è»éãèªåçã«ããã¹ãã«å€æããããããäœæããããšãææ¡ããŸããã ããã¯ãŸãã«ç®ãå ãç¬éã§ãã
é³å£°ããããã¹ããžã®ç¿»èš³
ãã®ãããªããããéçºããã®ã«ã©ããããã®æéãããããã¯ããããŸããã§ããããæž©ããå± å¿å°ã®è¯ããã£ããã«ãŒã ãšTelegramã®ãªãŒãã³ãœãŒã¹ã®TelegramããªãŒã©ã³ã¹ãµãŒãã¹ã®ãããã®è£ã§ååãªçµéšããããŸããã ããããããšãªããéçºã®ããã«åº§ã£ã-Telegam Bot APIã¢ãžã¥ãŒã«ãæ¥ç¶ãã段éã¯ã¹ã ãŒãºã«é²ãã ã 次ã¯ïŒ é³å£°èªèã¢ãžã¥ãŒã«-Googleã®ãé³å£°èªèAPIããæåã®ãªã³ã¯ã®äžã§æé«ã®ãµãŒãã¹ã®ãªã¹ããååŸããŸãã å é ã«ããã®ã¯ããŒã¿çã®Google Speech APIã§ãã
ãããã«ãã£ãŠãã¹ãŠã®ãã€ã¹ã¡ãã»ãŒãžãåä¿¡ããäœããã®åœ¢ã§Googleã«çŽæ¥éä¿¡ããŸãã ããããæ®å¿µãªããšã«ããã®ãµãŒãã¹ã䜿çšããããã®ã»ãšãã©ãã¹ãŠã®npmã¢ãžã¥ãŒã«ã¯æ代é ãã§ããããæ©èœããŸããã Googleã®å°é家ã«ãã£ãŠæžãããNode.jsã®çµã¿èŸŒã¿APIã䜿çšããããšããŠããŸã-åäœããŸãã èªèšŒã«ã¯äœããããŸããïŒ Googleã®ããã¥ã¡ã³ãããå€ãã®ãªãã·ã§ã³ãè©ŠããŠã¿ãŸãã-ã¡ãªã¿ã«ãããã50ã50ãå€ããªã£ãŠããããæ©èœããŠããŸãã-ããã«ããŒããããŸãã
ãšããã§ãããã«ç§ã䜿çšããã³ãŒãããããŸãïŒ
æŒããŠïŒ
const Speech = require('@google-cloud/speech'); const speech = new Speech({ projectId: 'voicy-151205', credentials: require('path/to/certificate/file.json') }); speech.startRecognition(filepath, { 'encoding': 'LINEAR16', 'sampleRate': 16000, 'languageCode': 'en-US', }) .then((results) => { const operation = results[0]; return operation.promise(); }) .then((transcription) => { console.log(transcription[0]); })
GoogleãªãŒãã£ãªã®åœ¢åŒãšå¶é
Googleã«éšéã掟é£ããã®ã¯ã©ãã§ããïŒ ãããTelegramãããªãŒãã£ãªãã¡ã€ã«ãååŸããŠSpeech APIãµãŒããŒã«éä¿¡ããå¿ èŠããããŸãã å æ°ïŒ Telegramã®éåžžã®.oga圢åŒã¯åãå ¥ããããŸãã-ãã³ãŒãããå¿ èŠããããŸãã ã¡ãã£ã¢å€æã«ã¯äœããããŸããïŒ ãã¡ãããffmpegã幌å°æãã芪ããã§ããŸããïŒç¶ã«æè¬ããŸããç¶ã¯æã圌ãç解ããŠãããŸããïŒã ããŒãã«æ¥ç¶ããæ¹æ³ã¯ïŒ ãã£ãšïŒ ãã®ããã«ç¹å¥ã«èª¿æŽãããnpmã¢ãžã¥ãŒã«ããããŸãã .ogaãã¡ã€ã«ãã©ã®åœ¢åŒã«å€æããå¿ èŠããããŸããïŒ Googleã¯.flacãåãå ¥ããå€æãè©Šè¡ããã¹ãŠãåãå ¥ããããGoogleãããã¹ãã§å¿çããæåããããšãå€æããŸããã
ããããããã«ãããŸããïŒ Googleã¯ãGoogle Cloud StorageãµãŒãã¹ã«ã¢ããããŒãããªãéãã60ç§ãè¶ ãããã¡ã€ã«ãããã¹ãã«å€æããŸããã ããã¯äœïŒ ããã«Googleããã°ã©ããŒã«ãã£ãŠæžãããã¢ãžã¥ãŒã«ãè©ŠããŠã¿ãŠãã ãããæ代é ãã®npmæ¢è£œãœãªã¥ãŒã·ã§ã³ã«ç®ãåããªãã§ãã ããã ããŠããã¡ã€ã«ã¯ã¢ããããŒãããããµãŒãã¹ã«ãã£ãŠåŠçãããããã¹ããè¿ãããŸãã ã¡ãªã¿ã«ãGoogleã«ã¯æéãšããå¥åŠãªæŠå¿µããããŸããäœããã®çç±ã§30ç§ã®ãªãŒãã£ãªãã¡ã€ã«ã¯60ç§ãšå®çŸ©ãããŠããŸãã 倧äžå€«ã§ã-30ç§ä»¥äžãã¡ã€ã«ãè©Šè¡ãã次ã®ã¬ãŒããèžã-Googleã¯LINEAR16ãšã³ã³ãŒãã§ã®ã¿é·ããã¡ã€ã«ãåãå ¥ããŸãã
LINEAR16ãšã¯äœã§ããïŒ ããã¥ã¡ã³ãã§ffmpegãæ¢ããŠããŸã-ãã®ãããªãã®ã¯ãããŸããã ããã§ãã ããã«åãçµã¿ãŸãã ãã®åœ¢åŒãŸãã¯ç£çšã®ã³ãŒããã¯ãæ¢ããŠããŸã-ããã¯ãã16ãããã®ç¬Šå·ä»ããªãã«ãšã³ãã£ã¢ã³ãããŒã¿ã§ããããšãããããŸããã ã³ã³ãã¥ãŒã¿ãŒãµã€ãšã³ã¹ã«é¢ããæ¬ãããã€ãèªãã§ãã16ãããããšã¯äœãããªãããªãã«ãšã³ãã£ã¢ã³ããªã®ããç¥ã£ãŠããã®ã¯è¯ãããšã§ãã ffmpegã®ãã®åœ¢åŒãäœã§ããããæ¢ããŠããŸã-ahaïŒâ s16leâïŒ ç§ãã¡ã¯å€æããããšããŸã-çµå±ã®ãšãããGoogleã¯ãããã·ã§ã³ãéæãããŸããããšããããã¹ããåãå ¥ããŠå¿çããŸãã
泚æïŒä»¥äžã¯ãå€æã«åœ¹ç«ã€ã³ãŒãã§ãïŒãã·ã³ã«ffmpegããã¬ã€ã³ã¹ããŒã«ããå¿ èŠããããŸãïŒïŒ
æŒããŠïŒ
const ffmpeg = require('fluent-ffmpeg'); const temp = require('temp'); ffmpeg.ffprobe(filepath, (err, info) => { const fileSize = info.format.duration; const output = temp.path({ suffix: '.flac' }); ffmpeg() .on('end', () => console.log(output)) .input(filepath) .setStartTime(0) .duration(fileSize) .output(output) .audioFrequency(16000) .toFormat('s16le') .run(); });
åçå
ããããããã¯äœã§ããïŒ Speech APIã䜿çšããããã®2ãã«ãšã¯äœã§ããïŒ åœŒãã¯Googleã§ãªãŒã¯ã䜿ã£ãŠå®å šã«ããã«è¡ããŸãããïŒ é³å£°ãããã¹ãã«ç¿»èš³ããã®ã«2æé以äžäœ¿çšããã®ã¯ã©ãããŠã§ããïŒ ããã¯ãŸã£ããæ©èœããŸãã-圌ãã¯ç§ã®ãããã100-1000ãã£ããã«è¿œå ããŸãããããŠç§ã¯ã©ãããã°ããã§ããïŒ æé£ã§ã¯ãããããµããŒãã®ç¯çŽã¯æ©èœããŸãã-ãã®èŠæš¡ã§ã¯ãããŸããã ã©ããããããæ¯æããå°ç¡ãã«ããå¿ èŠããããŸãã ãã£ããããšã«600ç§éã空ããŠãããGoogle Speech APIã®è²»çšã®è£åãæ±ããŸãã
Telegramã§ããããžã®æ¯æããåºå®ããæ¹æ³ã¯ïŒ æ確ãªæ瀺ãšåçåããŒã«ã¯ããŸã Telegramã«é ä¿¡ãããŠããŸãããå€éšã®åé¡ãäœããã®åœ¢ã§è§£æ±ºããå¿ èŠããããŸãã ã©ã®æ¯æããµãŒãã¹ã䜿çšããŸããïŒ ãŸããæè¿ãç§ã¯æ幎å°ã®åäžé·è ã«ãªã£ãç·ã«ã€ããŠèªãã -圌ã¯åœŒèªèº«ã®æ¯æããµãŒãã¹ãäœæããŸããã ã°ãŒã°ã«ãç§ãã¡ã¯èŠã-ã¹ãã©ã€ãããããŠããã䜿ãã ããã¯äœã§ããïŒ åœŒãã¯äŸ¿å©ãªãã§ãã¯ã¢ãŠããæã£ãŠããŸã-ãããããã¡ããç§ãã¡ã¯æšæºãã©ãŒã ã䜿çšããŸãããç§ãã¡ã¯èªåã§è¡ããŸãã
ããã³ããšã³ã
ã€ã³ã¿ã©ã¯ãã£ãããŒãžãäœæããå Žæ ç§ã¯iOSããã°ã©ããŒã§ãæè¿ãµãŒããŒéçºã«æ²¡é ããŸããããã®ããã足ãå°ããããã§ãã ããããããŠãããã³ããšã³ããéã«åããŸãããã©ããªäžå¹žã§ããïŒ ã°ãŒã°ã«ãã€ã³ã¿ã©ã¯ãã£ããªãµã€ããäœæããããã«ã©ã®ãã¯ãããžãŒã䜿çšãããŠãããã Angular 2ãjQueryãVanila.js-jQueryãæãã·ã³ãã«ã«èŠããŸããç¹ã«ããã䜿ããŸããç¹ã«ç§ã¯ãã€ãŠæ¥œããæéãéãããŠããããã§ãã Google YouTube jQueryãã¥ãŒããªã¢ã«-2ã3æéã®ãã¬ã·ã£ãã¯1åãé²è¡æ¹æ³ããã¥ãŒããªã¢ã«ãStack Overflowã®åçãç解ããŸãã
ããŽããã©ãŒã ãæ°è¡ã®ããã¹ãããã¿ã³ãªã©ããµã€ãã®æ§é ããã°ããæç»ããŸãã ã©ããã£ãŠããã®ïŒ Bootstrapã«ã€ããŠèããããšããããŸãã GoogleãBootstrap 3ã§ããã€ãã®ã¬ãã¹ã³ãè¡ããŸã-ãŸã Googleã§ãç»åã圢ç¶ããã¿ã³ãåºå®ããŸã-䞊ã¹æ¿ããŠããé©å¿æ§ããããŸãã ãµã€ãã®èæ¯ãçœããããã¯ãªãšã€ãã£ããªãã®ïŒãããã«ç°è²ããã£ããã®ïŒã«å€æŽãããµã€ãã®æºåãæŽããŸããã
JQueryã®æéïŒ å¥ã®ãããžã§ã¯ãã§æ¯æããè¡ãããšã«ããŸãã-ã³ãã³ãã©ã€ã³ã§ããšã¯ã¹ãã¬ã¹æ¯æãããèµ·åãããããžã§ã¯ããååŸããŸãã ãã°ããããã¹ã¯ãªãããã©ãã«çœ®ããïŒ ã©ããã£ãŠãçŽæ¥ãµã€ãã«ïŒ äœããééã£ãŠããŸã-å®éãããããå¥ã®ãã¡ã€ã«ã«è»¢éããããšãã§ããŸãããããç§ãã¡ã®ããããšã§ãã ãšã©ãŒåŠçãå¥ã®ã©ãã«ã«åºå®ããStripeãã©ãŒã ããã§ãã¯ãïŒæ®å¿µãªããšã«ãCheckoutã¢ãžã¥ãŒã«ã§å¿ èŠãªãã¹ãŠã®ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ãæäŸããŸãïŒãæ°ãããããžã§ã¯ããåãããŒã¿ããŒã¹ã«åºå®ããæ¯æãããã§ãã¯ããŸãã ãã¡ãããããªãã¿ã®ããã³ããšã³ãããŒã«éçºè ãããªããããWebããŒãžãæåã§ãªããŒãããåæ°ã¯ç¡æ°ã«ãããŸãã
ããã«ãå°ããªã³ã¡ã³ãã§ç§ãæã«å ¥ãããã¡ã€ã«ïŒæ éã«ãããŸããããã§ã¯ãªãã³ãŒãïŒã瀺ããŸãã
æŒããŠïŒ
index.hjs
<!DOCTYPE html> <html> <head> <title>Voicy payments</title> <!-- Bootstrap, jQuery, global.js, style.css Stripe--> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="/javascripts/global.js"></script> <script src="https://checkout.stripe.com/checkout.js"></script> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <!-- -, id , --> <img src="/images/logo.png" alt="Voicy" class="center-block"> <h1 class="center-block text-center">Chat ID:</h1> <h1 class="center-block text-center">{{ chatId }}</h1> <p class="text-center">{{ seconds }} seconds are left in this chat.</p> <p class="text-center">You can buy more seconds below.</p> <p class="text-center"><b>$0.4 per 200 seconds</b></p> <form> <div class="center"> <!-- â , --> <form class="form-inline" id="buy"> <div class="form-group"> <!--, , chatId --> <input type="hidden" name="chatId" value="{{ chatId }}"> <!-- , , --> <input type="number" class="form-control" name="numberOfSeconds" placeholder="Enter number of seconds"> <!-- â info, error success, global.js--> <small id="infoLabel" class="form-text text-info"></small> <small id="errorLabel" class="form-text text-danger"></small> <small id="successLabel" class="form-text text-success"></small> </div> <button type="submit" class="btn btn-primary center-block" id="buyButton">Buy</button> </form> </form> </form> </body> </html>
global.js
// $(document).ready(function() { // â , var chatId; var amount; // Stripe Checkout var handler = StripeCheckout.configure({ key: '***', image: 'https://pay.voicybot.com/images/stripe.png', locale: 'auto', // alipay: true, // , - AliPay // bitcoin: true, // â US closed: function() { // , info, stripe $("#successLabel").empty(); $("#errorLabel").empty(); }, token: function(token) { // , token // (, â ) $("#infoLabel").empty(); $("#successLabel").empty(); $("#errorLabel").empty(); // , $("#infoLabel").append('Processing payment on Voicy servers...'); // , index.js $.ajax({ type: 'POST', url: 'buy', data: { 'token': token.id, 'chatId': chatId, 'amount': amount }, dataType: 'json', encode: true }) .done(function(data) { // : â ""; â if (data['error']) { $("#infoLabel").empty(); $("#successLabel").empty(); $("#errorLabel").empty(); $("#errorLabel").append(data['error']); } else { $("#infoLabel").empty(); $("#successLabel").empty(); $("#errorLabel").empty(); $("#successLabel").append('Thank you for the payment!'); } }); } }); // Stripe, , window.addEventListener('popstate', function() { $("#infoLabel").empty(); $("#successLabel").empty(); $("#errorLabel").empty(); handler.close(); }); // â "Buy" $('form').submit(function(event) { event.preventDefault(); // var seconds = $('input[name=numberOfSeconds]').val(); // chatId = $('input[name=chatId]').val(); // chat id // â 200 , if (!seconds || seconds < 200) { $("#infoLabel").empty(); $("#successLabel").empty(); $("#errorLabel").empty(); $("#errorLabel").append('Please purchase at least 200 seconds'); } else { // â ... var purch = seconds * 0.002 * 100; amount = seconds; $("#infoLabel").empty(); $("#successLabel").empty(); $("#errorLabel").empty(); $("#infoLabel").append('Please pay at Stripe Checkout'); // ... Stripe handler.open({ name: 'Voicy Bot', description: 'Purchasing ' + seconds + ' seconds', currency: 'USD', amount: purch, // alipay: true, // bitcoin: true }); } }); });
index.js
// Express router HTTP jQuery const express = require('express'); const router = express.Router(); // db â , const db = require('../helpers/db'); // Stripe â const stripe = require("stripe")("***"); /** */ router.post('/buy', (req, res, next) => { // token stripe, const token = req.body.token; // id , const chatId = parseInt(req.body.chatId); // , const amount = parseInt(req.body.amount); var charge = stripe.charges.create({ amount: amount * 0.002 * 100, // source: token, currency: "USD", description: "Buying seconds for Voicy" }, (err, charge) => { if (err) { res.send({ error: err.message }); // jQuery } else { db.findChat(chatId) // id .then((chat) => { // , "" chat.seconds = parseInt(chat.seconds) + amount; // return chat.save() // .then((newChat) => { res.send({ success: true }); // "" jQuery }); }) .catch((err) => { res.send({ error: err.message }); // jQuery }) } }); }); /* */ router.get('/:id', (req, res, next) => { const chatId = parseInt(req.params.id); // id , db.findChat(chatId) // id .then((chat) => { // ? 404! if (!chat) { const err = new Error(); err.status = 404; err.message = 'No chat found'; throw err; } // ? ! return chat; }) .then((chat) => { // , id res.render('index', { chatId: chat.id, seconds: chat.seconds, }); }) .catch(err => next(err)); // ( ) });
ã¡ã€ã³ãŠã§ããµã€ã
åªãããããžã§ã¯ãã«ã¯å å®ãªãŠã§ããµã€ããå¿ èŠã§ããããã¹ãã£ã³ã°ã«ãéããããããããŸããã ãã¡ã€ã³åãè³Œå ¥ããGitHub Pagesã«çŽæ¥éä¿¡ããŸãã幞ããªããšã«ããã®çµéšã¯ä»¥åã®ãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ååã§ãã æšæºãã³ãã¬ãŒãã䜿çšããå¿ èŠãªããŒã¿ãå ¥åããŠãindex.htmlããããã«å€æŽããŸã-ããã ãã§ãã
NginxãšSSL
ããããæ¯æãæ¹æ³ãhttpsã§å©çšã§ããªãå ŽåããŠãŒã¶ãŒã¯ã©ã®ããã«ç§ãä¿¡é ŒããŸããïŒ å€§äžå€«-æ³³ããŸãããããã£ãŠããŸãïŒ ãµãŒããŒã§CertBotãèµ·åããå¿ èŠãªSSL蚌ææžãååŸããŸãã ãããŸã§ã®ãšãããã¢ããªã±ãŒã·ã§ã³ã¯ææã§å©çšå¯èœã§ã*ãã¡ã€ã³* .comïŒ3000-ããã§ãŠãŒã¶ãŒãèªå°ãã䟡å€ã¯ãããŸããã ãã¹ãŠã®ãªã¯ãšã¹ããhttpããhttpsã«ãªãã€ã¬ã¯ããããããã·ãããŒã80ãã3000ã«åæããããã«Nginxãæ§æããŸã-ãã§ãã¯ããŠããµã€ãã«ç§»åããåäœããŸãã
èå³ã®ããæ¹ã¯ãnginxèšå®ãã¡ã€ã«ãã芧ãã ããã
æŒããŠïŒ
# HTTP - HTTPS: server { listen 80; listen [::]:80 default_server ipv6only=on; return 301 https://$host$request_uri; } # HTTPS - Node.js : server { listen 443; server_name your_domain_name; ssl on; # Lets Encrypt: ssl_certificate /etc/letsencrypt/live/pay.voicybot.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pay.voicybot.com/privkey.pem; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers '***'; # localhost:3001: location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; proxy_pass http://localhost:3000/; proxy_ssl_session_reuse off; proxy_set_header Host $http_host; proxy_cache_bypass $http_upgrade; proxy_redirect off; } }
ãããã«
ã ããç§ã®è©±ã¯çªç¶äžæããŸãã-ãã¹ãŠãæºåãã§ããããšãå€æããŸããïŒ1å°ã®ãµãŒããŒããã¹ãŠã®ãã€ã¹ã¡ãã»ãŒãžãåä¿¡ããŠââããã¹ãã«å€æãã2å°ç®ãè»éã®åŠçæéã®å®å šãªæ¯æããæ åœããGitHubã¯ãããžã§ã¯ãã®ã¡ã€ã³ãµã€ããé åžããŸã ãã®èšäºã§èª¬æãããäž»ãªããšã¯ã補åãäœæããããã»ã¹ã¯ãæéã¯ããããŸãããã€ã³ã¿ãŒãããäžã®æ¢åã®ããŒã«ã®ãããã§40ã80æéã«åãŸãããšã§ãã
ãã®å°ããªãããžã§ã¯ãã«ã¯ä»¥äžãå«ãŸããããšãæãåºãããŠãã ããã
- é³å£°ãããã¹ãã«å€æããGoogleã®ãã¥ãŒã©ã«ãããã¯ãŒã¯
- ãã¶ã€ã³ãããã³ããšã³ãã®ã¹ãã«ãªãã§äœæãããåªããWebãµã€ã
- ã¡ãªã¿ã«ããã¹ãŠã®ãã©ãŠã¶ã§åäœããAliPayããããã³ã€ã³ã§ãåäœããã¹ããŒããªæ¯æãããŒã«
- ãã£ãããšãŠãŒã¶ãŒã®ããŒã¿ããŒã¹ãåžžã«çµ±èšãèŠãããšãã§ããŸã
- ç°ãªã圢åŒéã§ãªãŒãã£ãªãã¡ã€ã«ãå€æãã
- SSLãåããé«åºŠãªãµãŒããŒã2ã€ã®è€éãªã¢ããªã±ãŒã·ã§ã³ãçºç
- 人çèŠå ããªãïŒãã¹ãŠãèªåçã«æ©èœãã
ãŸã èªåã®è£œåãäœæããã®ã«ååãªã¹ãã«ããªããšæã£ãŠãããªããèŠãŠåã£ãŠããã¹ãŠããã§ã«ããªãã®ããã«è¡ãããŠããŸãã åã2000幎ãšã¯å¯Ÿç §çã«ãçŸåšã補åã®äœæã«ã¯ã¢ã«ãŽãªãºã ãšããŒã¿æ§é ã®æ·±ãç¥èã¯å¿ èŠãããŸããã ããã§ãããªãã¯äœãåŸ ã£ãŠããŸããïŒ
è¬èŸ
æåŸãŸã§èªãã§ãããŠããããšãïŒ ãã®èšäºã«é¢ãããã¹ãŠã®ã³ã¡ã³ãã«åãã§ãçãããŸãã ããã¯Habrahabrã®ã«ãŒã«ã«åããããããããèªäœãžã®ãªã³ã¯ã¯æ·»ä»ããŸããïŒå®å šã«æ©èœããŠããŸããïŒã