犁欲的なWebGoずJSのプロトタむプフリヌマヌケット

スクリヌンショット







みなさん、こんにちは。最新のWebアプリケヌションの可胜性に぀いおの私の考えの結果を共有したいず思いたす。 䟋ずしお、コミック甚の掲瀺板の蚭蚈を怜蚎しおください。 ある意味では、問題の補品は、オタクずシンパサむザヌの聎衆向けに蚭蚈されおおり、むンタヌフェむスで自由を瀺すこずができたす。 それどころか、技術コンポヌネントでは、现郚ぞの泚意が必芁です。







実際、挫画では䜕もわかりたせんが、フリヌマヌケット、特にれロで人気のあったフォヌラム圢匏は倧奜きです。 したがっお、次の結論が流れる仮定おそらく誀りは1぀にすぎたせん。アプリケヌションずの察話の䞻なタむプは衚瀺であり、2番目のタむプはアナりンスずディスカッションの投皿です。







私たちの目暙は、シンプルなアプリケヌションを䜜成するこずです。 技術的ノりハり ただし、珟代の珟実ず䞀臎する䜙分なホむッスル。 私が達成したい䞻な芁件は次のずおりです。







  1. サヌバヌ偎







    aクラむアントぞのナヌザヌデヌタの保存、怜蚌、送信の機胜を実行する

    b䞊蚘の操䜜は、蚱容量のリ゜ヌス時間を含むを消費したす

    cアプリケヌションずデヌタが䞀般的な攻撃ベクトルから保護されおいる

    dサヌドパヌティのクラむアントずサヌバヌ間察話のためのシンプルなAPI

    eクロスプラットフォヌムで簡単な展開







  2. クラむアント偎







    aコンテンツの䜜成ず䜿甚に必芁な機胜を提䟛したす

    bむンタヌフェむスは、通垞の䜿甚、アクションぞの最小パス、画面ごずの最倧デヌタ量に䟿利です。

    cサヌバヌずの通信倖で、この状況ですべおの可胜な機胜が利甚可胜

    dむンタヌフェむスは、再起動しお埅機するこずなく、状態ずコンテンツの珟圚のバヌゞョンを衚瀺したす

    dアプリケヌションを再起動しおも、その状態には圱響したせん

    f可胜であれば、DOM芁玠ずJSコヌドを再利甚したす

    g実行時にサヌドパヌティのラむブラリずフレヌムワヌクを䜿甚したせん

    hレむアりトは、アクセシビリティ、パヌサヌなどのセマンティックです。

    iメむンコンテンツのナビゲヌションには、URLずキヌボヌドを䜿甚しおアクセスできたす









私の意芋では、論理的な芁件、および最新のアプリケヌションは、ある皋床これらの条件を満たしおいたす。 私たちに䜕が起こるか芋おみたしょう投皿の最埌にある゜ヌスずデモぞのリンク。







譊告
  • 蚱可なくデモで䜿甚された画像の䞍明な䜜者、ならびにGösseG.、Prozorovskaya B. D.、および出版瀟「フィレンツェ図曞通パノレンコフ」の䜜品「Siddhartha」からの抜粋を䜿甚したこずに぀いお謝眪したいず思いたす。
  • 著者は本物のプログラマヌではありたせん。䜕をしおいるのかわからない堎合、このプロゞェクトで䜿甚されおいるコヌドやテクニックを䜿甚するこずはお勧めしたせん。
  • コヌドのスタむルをおaびしたす;もっず読みやすく、明らかに曞かれおいるかもしれたせんが、これは面癜くありたせん。 圌らが蚀うように、魂ず友人のためのプロゞェクト。
  • たた、特に英語のテキストでは、識字率に぀いおも謝眪したす。 May Hartからの幎。
  • 提瀺されたプロトタむプの性胜は、[クロム70; linux x86_64; 1366x768]、゚ラヌメッセヌゞに぀いお、他のプラットフォヌムおよびデバむスのナヌザヌに非垞に感謝したす。
  • これはプロトタむプであり、議論のための提案されたトピックです-アプロヌチず原則、私は実装ず矎的偎面のすべおの批刀に議論を䌎うこずを求めたす。


サヌバヌ



サヌバヌの蚀語はgolangです。 優れた暙準ラむブラリずドキュメントを備えたシンプルで高速な蚀語...少し面倒です。 最初の遞択ぱリキシル/アヌランにかかっおいたしたが、私は比范的ゎヌを知っおいたので、それを耇雑にしないこずに決めたしたそしお必芁なパッケヌゞはゎヌのためだけでした。







go-communityでのWebフレヌムワヌクの䜿甚は掚奚されたせん 圓然 、認める䟡倀がありたす。劥協案を遞択しおlabstack / echoマむクロフレヌムワヌクを䜿甚するこずで、ルヌチンの量を枛らし、パフォヌマンスがあたり䜎䞋しないように思えたす。







デヌタベヌスずしおtidwall / buntdbを䜿甚したす。 第䞀に、組み蟌み゜リュヌションはより䟿利でオヌバヌヘッドのコストを削枛し、第二に、むンメモリ+キヌ/倀- おしゃれでスタむリッシュ 高速でキャッシュ䞍芁。 JSONでデヌタを保存および提䟛し、倉曎時にのみ怜蚌したす。







第2䞖代のi3では、組み蟌みロガヌは0.5〜10ミリ秒のさたざたな芁求の実行時間を衚瀺したす。 同じマシンでwrkを実行しおも、目的には十分な結果が埗られたす。







➜ comico git:(master) wrk -t2 -c500 -d60s http://localhost:9001/pub/mtimes Running 1m test @ http://localhost:9001/pub/mtimes 2 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 20.74ms 16.68ms 236.16ms 72.69% Req/Sec 13.19k 627.43 15.62k 73.58% 1575522 requests in 1.00m, 449.26MB read Requests/sec: 26231.85 Transfer/sec: 7.48MB
      
      





 ➜ comico git:(master) wrk -t2 -c500 -d60s http://localhost:9001/pub/goods Running 1m test @ http://localhost:9001/pub/goods 2 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 61.79ms 65.96ms 643.73ms 86.48% Req/Sec 5.26k 705.24 7.88k 70.31% 628215 requests in 1.00m, 8.44GB read Requests/sec: 10454.44 Transfer/sec: 143.89MB
      
      





プロゞェクト構造



comico / modelパッケヌゞは3぀のファむルに分かれおいたす。

model.go-デヌタ型ず䞀般的な機胜の説明が含たれたす。䜜成/曎新buntdbはこれらの操䜜を区別せず、レコヌドの存圚を手動で確認したす、怜蚌、削陀、1぀のレコヌドの取埗、リストの取埗。

rules.go-特定のタむプおよびロギング機胜の怜蚌ルヌルが含たれおいたす。

files.go-画像を操䜜したす。

Mtimesタむプは、デヌタベヌス内の残りのタむプの最埌の倉曎に関するデヌタを栌玍し、どのデヌタが倉曎されたかをクラむアントに䌝えたす。







comico / bdパッケヌゞには、デヌタベヌスずやり取りするための䞀般化された関数が含たれおいたす䜜成、削陀、遞択など。Buntdbは、ファむルぞのすべおの倉曎をテキスト圢匏で保存したすこの堎合、1秒に1回。 dbファむルは線集されず、トランザクションが成功した堎合の倉曎が最埌に远加されたす。 デヌタの敎合性に違反する私の詊みはすべお倱敗したした。最悪の堎合、最埌の1秒の倉曎は倱われたす。

実装では、各タむプは個別のファむル内の個別のデヌタベヌスに察応したすメモリに排他的に保存され、再起動時にれロにリセットされるログを陀く。 これは䞻に、バックアップず管理の䟿利さ、小さなプラス-1぀のタむプのデヌタのみぞのブロックアクセスを線集するためのオヌプントランザクションによるものです。

このパッケヌゞは、たずえばSQLなどの別のデヌタベヌスを䜿甚しお、同様のパッケヌゞに簡単に眮き換えるこずができたす。 これを行うには、次の機胜を実装するだけで十分です。







 func Delete(db byte, key string) error func Exist(db byte, key string) bool func Insert(db byte, key, val string) error func ReadAll(db byte, pattern string) (str string, err error) func ReadOne(db byte, key string) (str string, err error) func Renew(db byte, key string) (err error, newId string)
      
      





comico / cnstパッケヌゞには、すべおのパッケヌゞに必芁な定数デヌタ型、アクション型、ナヌザヌ型が含たれおいたす。 さらに、このパッケヌゞには、サヌバヌが倖郚の䞖界に応答するための人間が読めるすべおのメッセヌゞが含たれおいたす。







comico / serverパッケヌゞにはルヌティング情報が含たれおいたす。 たた、数行Echo開発者のおかげ、JWTを䜿甚した承認、CORS、CSPヘッダヌ、ロガヌ、静的配垃、gzip、ACME自動蚌明曞などが構成されおいたす。







API゚ントリポむント



URL デヌタ 説明
get / pub /商品|投皿|ナヌザヌ| cmnts |ファむル - 関連するお知らせ、投皿、ナヌザヌ、コメント、ファむルの配列を取埗する
get / pub / mtimes - 各デヌタ型の最終倉曎時刻を取埗する
投皿/パブ/ログむン {id *ログむン、pass *パスワヌド} JWTトヌクンずその期間を返したす
投皿/パブ/パス {id *、pass *} デヌタが正しい堎合、新しいナヌザヌを䜜成したす
put / api / pass {id *、pass *} パスワヌド曎新
投皿| put / api / goods {id *、auth *、title *、type *、price *、text *、images[]、Table{keyvalue}} 広告を䜜成/曎新
投皿| put / api / posts {id *、auth *、title *、type *、text *} フォヌラム投皿の䜜成/曎新
投皿| put / api / users {id *、タむトル、タむプ、ステヌタス、スクラむブ[]、無芖[]、テヌブル{キヌ倀}} ナヌザヌの䜜成/曎新
投皿/ API / cmnts {id *、auth *、owner *、type *、to、text *} コメント䜜成
delete / api /商品|投皿|ナヌザヌ| cmnts/ [id] - IDを持぀゚ントリを削陀したす
get / api / activity - 珟圚のナヌザヌの受信コメントの最終読み取り時間を曎新したす
get / api /賌読|無芖/ [タグ] - サブスクリプションのリストにナヌザヌタグを远加たたは削陀したす存圚する堎合/無芖
投皿/ API /アップロヌド/商品|ナヌザヌ マルチパヌト名前、ファむル 写真広告/ナヌザヌアバタヌをアップロヌドしたす


*-必須フィヌルド

api-認蚌が必芁、pub-いいえ







䞊蚘ず䞀臎しないget芁求では、サヌバヌはディレクトリ内のファむルを静的に怜玢したすたずえば、/ img / *-images、/ index.html-client。

すべおのAPIポむントは、成功した堎合は200の応答コヌド、゚ラヌが発生した堎合は400たたは404、必芁な堎合は短いメッセヌゞを返したす。

アクセス暩は簡単です。゚ントリの䜜成は承認されたナヌザヌが利甚でき、䜜成者ずモデレヌタヌは線集でき、管理者はモデレヌタヌを線集しお任呜できたす。

APIには最も単玔なアンチバンダルが装備されおいたすアクションはナヌザヌIDずIPずずもに蚘録され、頻繁にアクセスする堎合は、少し埅぀ように求める゚ラヌが返されたすパスワヌドの掚枬に圹立ちたす。







お客様



リアクティブWeb'aのコンセプトが奜きです。最新のサむト/アプリケヌションのほずんどは、このコンセプトのフレヌムワヌク内で、たたは完党に静的に行われるべきだず思いたす。 䞀方、メガバむトのJSコヌドを䜿甚した単玔なサむトは意気消沈するしかありたせん。 私の意芋では、このそしおそれだけではない問題はSvelteによっお解決できる。 このフレヌムワヌクたたはリアクティブむンタヌフェむスを構築するための蚀語は、必芁な機胜においおVueに劣りたせんが、吊定できない利点がありたす-コンポヌネントはバニラJSにコンパむルされ、バンドルのサむズず仮想マシンbundle.min.js.gzの負荷の䞡方を削枛したすフリヌマヌケットは控えめで、今日の基準では24KBです。 詳现は公匏文曞に蚘茉されおいたす 。







フリヌマヌケットのクラむアントパヌトずしおSvelteJSフリヌマヌケットを遞択したす。リッチハリスずプロゞェクトのさらなる発展に最善を尜くしたす。







PS私は誰かを怒らせたくない。 各スペシャリストず各プロゞェクトには独自のツヌルがあるず確信しおいたす。







顧客/デヌタ



URL



ナビゲヌションに䜿甚したす。 耇数ペヌゞのドキュメントをシミュレヌトするのではなく、代わりに、ク゚リパラメヌタでハッシュペヌゞを䜿甚したす。 遷移の堎合、jsなしで通垞の<a>を䜿甚できたす。







セクションはデヌタタむプに察応したす /goods 、 /posts 、 /users 。

パラメヌタヌId = record_id 、Page = page_number 、Search = search_query 。







いく぀かの䟋









実装における解析ずURL生成の機胜は次のようになりたす。







 window.addEventListener('hashchange', function() { const hash = location.hash.slice(1).split('?'), result = {} if (!!hash[1]) hash[1].split('&').forEach(str => { str = str.split('=') if (!!str[0] && !!str[1]) result[decodeURI(str[0]).toLowerCase()] = decodeURI(str[1]).toLowerCase() }) result.type = hash[0] || 'goods' store.set({ hash: result }) }) function goto({ type, id, page, search }) { const { hash } = store.get(), args = arguments[0], query = [] new Array('id', 'page', 'search').forEach(key => { const value = args[key] !== undefined ? args[key] : hash[key] || null if (value !== null) query.push(key + '=' + value) }) location.hash = (type || hash.type || 'goods') + (!!query.length ? '?' + query.join('&') : '') }
      
      





API



サヌバヌずデヌタを亀換するには、フェッチAPIを䜿甚したす。 曎新されたレコヌドを短い間隔でダりンロヌドするには、 / pub / mtimesにリク゚ストを行いたす。いずれかのタむプの最終倉曎時刻がロヌカルのものず異なる堎合、このタむプのリストをロヌドしたす。 はい、SSEたたはWebSocketsを介した曎新の通知ず増分ロヌドを実装するこずができたしたが、この堎合は通知なしで実行できたす。 私たちは䜕を埗たした







 async function GET(type) { const response = await fetch(location.origin + '/pub/' + type) .catch(() => ({ ok: false })) if (type === 'mtimes') store.set({ online: response.ok }) return response.ok ? await response.json() : [] } async function checkUpdate(type, mtimes, updates = {}) { const local = store.get()._mtimes, net = mtimes || await GET('mtimes') if (!net[type] || local[type] === net[type]) return const value = updates['_' + type] = await GET(type) local[type] = net[type]; updates._mtimes = local if (!!value && !!value.sort) store.set(updates) } async function checkUpdates() { setTimeout(() => checkUpdates(), 30000) const mtimes = await store.GET('mtimes') new Array('users', 'goods', 'posts', 'cmnts', 'files') .forEach(type => checkUpdate(type, mtimes)) }
      
      





フィルタリングずペヌゞネヌションには、ナビゲヌションデヌタに基づいお蚈算されたSvelteプロパティを䜿甚したす。 蚈算された倀の方向は次のずおりです items サヌバヌからのレコヌドの配列=> ignoreItems 珟圚のナヌザヌの無芖リストに基づいおフィルタヌされたレコヌド=> scribedItems このモヌドが有効になっおいる堎合、サブスクリプションのリストによっおレコヌドをフィルタヌしたす=> curItemおよびcurItems 珟圚のレコヌドを蚈算したすセクションに応じお=> filtersItems 怜玢ク゚リに応じおレコヌドをフィルタリングしたす。レコヌドが1぀しかない堎合-コメントをフィルタリングしたす=> maxPage ペヌゞあたり12レコヌド/コメントに基づいおペヌゞ数を蚈算したす=> pagedItem 最終配列を返したす 珟圚のペヌゞ番号に基づいた投皿/コメント。







コメントず画像 commentsず_images は個別に蚈算され、タむプず所有者レコヌドごずにグルヌプ化されたす。







蚈算は自動的に行われ、関連するデヌタが倉曎された堎合にのみ、䞭間デヌタは垞にメモリ内にありたす。 これに関しお、䞍愉快な結論を出したす-倧量の情報および/たたは頻繁な曎新のために、倧量のリ゜ヌスを費やすこずができたす。







キャッシュ



オフラむンアプリケヌションを䜜成するずいう決定に埓っお、レコヌドの保存ずlocalStorageの状態のいく぀かの偎面、CacheStorageのむメヌゞファむルを実装したす。 localStorageの操䜜は非垞に簡単です。「_」プレフィックスを持぀プロパティは、倉曎時に再起動時に自動的に保存および埩元されるこずに同意したす。 次に、゜リュヌションは次のようになりたす。







 store.on('state', ({ changed, current }) => { Object.keys(changed).forEach(prop => { if (!prop.indexOf('_')) localStorage.setItem(prop, JSON.stringify(current[prop])) }) }) function loadState(state = {}) { for (let i = 0; i < localStorage.length; i++) { const prop = localStorage.key(i) const value = JSON.parse(localStorage.getItem(prop) || 'null') if (!!value && !prop.indexOf('_')) state[prop] = value } store.set(state) }
      
      





ファむルはもう少し耇雑です。 たず、サヌバヌから送られおくるすべおの実際のファむルのリスト䜜成時間を含むを䜿甚したす。 このリストを曎新するずき、叀い倀ず比范し、新しいファむルをCacheStorageに入れ、そこから叀いファむルを削陀したす。







 async function cacheImages(newFiles) { const oldFiles = JSON.parse(localStorage.getItem('_files') || '[]') const cache = await caches.open('comico') oldFiles.forEach(file => { if (!~newFiles.indexOf(file)) { const [ id, type ] = file.split(':') cache.delete(`/img/${type}_${id}_sm.jpg`) }}) newFiles.forEach(file => { if (!~oldFiles.indexOf(file)) { const [ id, type ] = file.split(':'), src = `/img/${type}_${id}_sm.jpg` cache.add(new Request(src, { cache: 'no-cache' })) }}) }
      
      





次に、サヌバヌに接続せずにファむルがCacheStorageから取埗されるように、フェッチの動䜜を再定矩する必芁がありたす。 これを行うには、ServiceWorkerを䜿甚する必芁がありたす。 同時に、他のファむルがキャッシュされるように蚭定しお、サヌバヌずの通信以倖で機胜するようにしたす。







 const CACHE = 'comico', FILES = [ '/', '/bundle.css', '/bundle.js' ] self.addEventListener('install', (e) => { e.waitUntil(caches.open(CACHE).then(cache => cache.addAll(FILES)) .then(() => self.skipWaiting())) }) self.addEventListener('fetch', (e) => { const r = e.request if (r.method !== 'GET' || !!~r.url.indexOf('/pub/') || !!~r.url.indexOf('/api/')) return if (!!~r.url.lastIndexOf('_sm.jpg') && e.request.cache !== 'no-cache') return e.respondWith(fromCache(r)) e.respondWith(toCache(r)) }) async function fromCache(request) { return await (await caches.open(CACHE)).match(request) || new Response(null, { status: 404 }) } async function toCache(request) { const response = await fetch(request).catch(() => fromCache(request)) if (!!response && response.ok) (await caches.open(CACHE)).put(request, response.clone()) return response }
      
      





それは少し䞍噚甚に芋えたすが、その機胜を実行したす。







クラむアント/むンタヌフェヌス



コンポヌネント構造

index.html | main.js

== header.html-ロゎ、ステヌタスバヌ、メむンメニュヌ、䞋郚ナビゲヌションメニュヌ、コメント送信フォヌムが含たれおいたす

== aside.html-すべおのモヌダルコンポヌネントのコンテナです

==== goodForm.html-広告を远加および線集するためのフォヌム

==== userForm.html-珟圚のナヌザヌのフォヌムを線集

====== tableForm.html-衚圢匏のデヌタを入力するためのフォヌムのフラグメント

==== postForm.html-フォヌラム投皿のフォヌム

==== login.html-ログむン/登録フォヌム

==== activity.html-珟圚のナヌザヌ宛のコメントを衚瀺したす

==== goodImage.html-メむンおよび远加の写真広告を衚瀺

== main.html-メむンコンテンツのコンテナ

==== goods.html-リストたたは単䞀の発衚カヌド

==== users.html-ナヌザヌも同じ

==== posts.html-明らかだず思う

==== cmnts.html-珟圚の投皿に察するコメントのリスト

====== cmntsPager.html-コメントのペヌゞネヌション









顧客/管理



キヌボヌドを䜿甚しお制埡するには、次の組み合わせを䜿甚したす。

Alt + s / Alt + a-レコヌドのペヌゞを前埌に切り替えたす。1぀のレコヌドがコメントのペヌゞを切り替えたす。

Alt + w / Alt + q-次/前のレコヌド存圚する堎合に移動し、リストモヌド、単䞀レコヌドおよび画像ビュヌで動䜜したす

Alt + x / Alt + z-ペヌゞを䞊䞋にスクロヌルしたす。 画像衚瀺モヌドでは、画像を呚期的に前埌に切り替えたす

゚スケヌプ -開いおいる堎合はモヌダルりィンドりを閉じ、単䞀の゚ントリが開いおいる堎合はリストに戻り、リストモヌドで怜玢ク゚リをキャンセルしたす

Alt + c-珟圚のモヌドに応じお、怜玢たたはコメントフィヌルドにフォヌカスしたす

Alt + v-単䞀の広告の写真衚瀺モヌドを有効/無効にしたす

Alt + r-承認されたナヌザヌの受信コメントのリストを開く/閉じる

Alt + t-明るいテヌマず暗いテヌマを切り替えたす

Alt + g-広告のリスト

Alt + u-ナヌザヌ

Alt + P-フォヌラム

倚くのブラりザでは、これらの組み合わせがブラりザ自䜓によっお䜿甚されおいるこずを知っおいたすが、私のクロムでは、もっず䟿利なものを思い付くこずができたせんでした。 私はあなたの提案に喜んでいるでしょう。







キヌボヌドに加えお、もちろんブラりザコン゜ヌルを䜿甚できたす。 たずえば、 store.goBack 、 store.nextPage 、 store.prevPage 、 store.nextItem 、 store.prevItem 、 store.searchstringValue 、 store.checkUpdate 'goods' || 'ナヌザヌ '||'投皿 '||'ファむル '||' cmnts ' -名前が意味するこずを行いたす。 store.get。commentsおよびstore.get._ images-グルヌプ化されたファむルずコメントを返したす。 store.get.ignoredItemsおよびstore.get。scribedItemsは、無芖しお远跡するレコヌドのリストです。 すべおの䞭間デヌタおよび蚈算デヌタの完党なリストは、 store.getから入手できたす。 誰もこれを真剣に必芁ずする人はいないず思いたすが、たずえば、ナヌザヌごずに゚ントリをフィルタリングし、コン゜ヌルから削陀するず非垞に䟿利なように思えたす。







おわりに



ここで、プロゞェクトの知り合いを終了できたす;゜ヌスコヌドで詳现を確認できたす。 その結果、ほずんどのバリデヌタ、セキュリティ、速床、可甚性などのチェッカヌで、かなり高速でコンパクトなアプリケヌションが埗られたした。タヌゲットを絞った最適化なしで良い結果を瀺しおいたす。

プロトタむプで䜿甚されるアプリケヌションを線成するアプロヌチがどの皋床正圓化されるか、萜ずし穎は䜕か、根本的に異なる方法で䜕を実装するのか、コミュニティの意芋を知りたいず思いたす。

゜ヌスコヌド、サンプルのむンストヌル手順、およびデモはこちら どうぞ 砎壊する 刑法の枠組みでテストするため。







远蚘。 結論ずしおは少し商業的です。 そのようなレベルで、お金のためにプログラミングを始めるこずは本圓に可胜ですか そうでない堎合、たず第䞀に䜕を探すべきか、もしそうなら、圌らは今、䌌たようなスタックで面癜い䜜品を探しおいる堎所を教えおください。 ありがずう







远蚘。 お金ず仕事に぀いおもう少し。 このアむデアはいかがですか絊䞎に぀いお興味深いプロゞェクトに取り組む準備ができおいるず仮定したすが、支払いが垂堎を倧幅に䞋回っおいる堎合、雇甚䞻の競争盞手であるタスクずその支払いに関するデヌタは公開されたす可甚性ずパフォヌマンスの品質を評䟡するためのコヌドが望たしいより高い堎合、タスクを実行するために倚くのお金を提䟛するこずができたす-倚くのパフォヌマヌは、䜎䟡栌でサヌビスを提䟛するこずができたす。 状況によっおは、このようなスキヌムは、垂堎ITをより最適か぀公正にバランスさせるのでしょうか








All Articles