diff --git a/Projects/Superalgos/Schemas/Docs-Topics/integrations-001-telegram-announcements.json b/Projects/Superalgos/Schemas/Docs-Topics/integrations-001-telegram-announcements.json index 2472e61a2..46c5fda78 100644 --- a/Projects/Superalgos/Schemas/Docs-Topics/integrations-001-telegram-announcements.json +++ b/Projects/Superalgos/Schemas/Docs-Topics/integrations-001-telegram-announcements.json @@ -4,7 +4,14 @@ "type": "Telegram Announcements", "definition": { "text": "Setup a Telegram bot to broadcast the activity of trading sessions to a Telegram group. You may produce plain-text or dynamic-content announcements at every event in your trading systems.", - "updated": 1611484869105 + "updated": 1611484869105, + "translations": [ + { + "language": "ID", + "text": "Penyiapan Telegram bot untuk membroadcast aktivitas dari sesi trading ke grup Telegram. Kamu dapat membuat plain-text atau pengumuman berbentuk dynamic-contenct di setiap event pada trading sistem milikmu.", + "updated": 1616926732019 + } + ] }, "paragraphs": [ { @@ -14,15 +21,36 @@ }, { "style": "Text", - "text": "The announcements feature allows users to set up notifications tied to specific events, and triggered once each particular event becomes active while running any of the available types of trading sessions." + "text": "The announcements feature allows users to set up notifications tied to specific events, and triggered once each particular event becomes active while running any of the available types of trading sessions.", + "translations": [ + { + "language": "ID", + "text": "Fitur pengumuman memungkinkan pengguna untuk mengatur pemberitahuan yang terkait dengan event tertentu, dan terpicu setelah setiap event menjadi aktif saat menjalankan salah satu jenis sesi trading yang tersedia.", + "updated": 1616927035635 + } + ] }, { "style": "Text", - "text": "You may use this feature to stay informed about the actions of your strategies while trading live, or to broadcast signals over a Telegram group while paper trading, for instance." + "text": "You may use this feature to stay informed about the actions of your strategies while trading live, or to broadcast signals over a Telegram group while paper trading, for instance.", + "translations": [ + { + "language": "ID", + "text": "Kamu akan menggunakan fitur ini tetap mendapat informasi tentang tindakan dari strategi saat live trading, atau untuk membroadcast sinyal melalui grup Telegram, misalnya paper trading.", + "updated": 1616927218638 + } + ] }, { "style": "Text", - "text": "Supported events are:" + "text": "Supported events are:", + "translations": [ + { + "language": "ID", + "text": "Events yang didukung:", + "updated": 1616927255808 + } + ] }, { "style": "List", @@ -42,20 +70,48 @@ }, { "style": "Text", - "text": "In addition, you can implement announcements at the level of stop and take profit phases, a particular case that shall be discussed too." + "text": "In addition, you can implement announcements at the level of stop and take profit phases, a particular case that shall be discussed too.", + "translations": [ + { + "language": "ID", + "text": "Selain itu, kamu dapat mengimplementasikan pengumuman di level fase stop dan take profit, hal-hal lain juga akan kita bahas nantinya.", + "updated": 1616927456192 + } + ] }, { "style": "Text", - "text": "The current implementation is based on broadcasting announcements via Telegram bots. The system uses Telegram’s bots API to interact with a Telegram bot you will create. The bot will be added as a user in the Telegram group of your choice in which it will deliver the announcements as per the configuration you will set up in the system." + "text": "The current implementation is based on broadcasting announcements via Telegram bots. The system uses Telegram’s bots API to interact with a Telegram bot you will create. The bot will be added as a user in the Telegram group of your choice in which it will deliver the announcements as per the configuration you will set up in the system.", + "translations": [ + { + "language": "ID", + "text": "Implementasi pada saat ini berdasar pada membroadcast pengumuman dari Telegram bot. Sistem menggunakan Telegram bot API untuk menghubungkan Telegram bot yang kamu buat. Bot akan ditambahkan sebagai user di Telegram grup pilihanmu yang akan mengirimkan pengumuman sesuai konfigurasi yang kamu atur pada sistem.", + "updated": 1616927659463 + } + ] }, { "style": "Title", - "text": "Setting Up a Telegram Bot and a Telegram Group" + "text": "Setting Up a Telegram Bot and a Telegram Group", + "translations": [ + { + "language": "ID", + "text": "Menyiapkan Telegram Bot dan Telegram Grup", + "updated": 1616927728752 + } + ] }, { "style": "Text", "text": "Telegram’s documentation explains the details of how to use Telegram bots:", - "updated": 1611485108327 + "updated": 1611485108327, + "translations": [ + { + "language": "ID", + "text": "Dokumentasi Telegram menjelaskan secara detail cara menggunakan Telegram bot:", + "updated": 1616927702979 + } + ] }, { "style": "Link", @@ -64,62 +120,153 @@ }, { "style": "Text", - "text": "You may choose to read Telegram’s documentation or simple follow the next few steps, which have been extracted for your convenience:" + "text": "You may choose to read Telegram’s documentation or simple follow the next few steps, which have been extracted for your convenience:", + "translations": [ + { + "language": "ID", + "text": "Kamu dapat memilih untuk membaca dokumentasi Telegram atau mengikuti beberapa step berikut, yang telah diekstrak untuk kemudahanmu:", + "updated": 1616927824426 + } + ] }, { "style": "List", "text": "1. Go to Telegram and find the user @BotFather: You may use the link or simply search for the user.", - "updated": 1611485257909 + "updated": 1611485257909, + "translations": [ + { + "language": "ID", + "text": "1. Pergi ke Telegram dan cari user @BotFather: Kamu dapat menggunakan tautan atau langsung mencari user.", + "updated": 1616927906032 + } + ] }, { "style": "List", "text": "2. Type and send /newbot: BotFather will ask you to pick a name for your bot. Once the name is set, it will respond with the token (a text string) to access the HTTP API.", - "updated": 1611485277898 + "updated": 1611485277898, + "translations": [ + { + "language": "ID", + "text": "2. Ketik dan kirimkan /newbot: BotFather akan memintamu untuk memasukkan nama bot. Setelah ditetapkan, ia akan merespon dengan token (sebuah text string) untuk mengakses HTTP API.", + "updated": 1616928012542 + } + ] }, { "style": "Text", - "text": "You will need this token at a later time." + "text": "You will need this token at a later time.", + "translations": [ + { + "language": "ID", + "text": "Kamu akan membuuhkan token ini nantinya.", + "updated": 1616928036024 + } + ] }, { "style": "List", "text": "3. Create a Telegram: Your bot will broadcast the announcements here.", - "updated": 1611485421498 + "updated": 1611485421498, + "translations": [ + { + "language": "ID", + "text": "3. Buat Telegram Grup: Bot-mu akan membroadcast pengumuman disini nantinya.", + "updated": 1616928100241 + } + ] }, { "style": "List", "text": "4. Add your bot in the group: And add @myidbot as user in the group too.", - "updated": 1611485472896 + "updated": 1611485472896, + "translations": [ + { + "language": "ID", + "text": "4. Tambahkan bot-mu kedalam grup: Dan tambahkan juga @myidbot sebagai user didalamnya.", + "updated": 1616928168243 + } + ] }, { "style": "List", "text": "5. Type and send /getgroupid in the group: IDBot will answer with the group’s ID.", - "updated": 1611485491256 + "updated": 1611485491256, + "translations": [ + { + "language": "ID", + "text": "5. Ketik dan kirimkan /getgroupid didalam grup: IDBot akan menjawab dengan sebuah group’s ID.", + "updated": 1616928215518 + } + ] }, { "style": "Text", - "text": "You will need this ID at a later time." + "text": "You will need this ID at a later time.", + "translations": [ + { + "language": "ID", + "text": "Kamu juga akan membutuhkan ID ini nantinya.", + "updated": 1616928242124 + } + ] }, { "style": "Title", - "text": "Setting Up the Telegram Bot in Superalgos" + "text": "Setting Up the Telegram Bot in Superalgos", + "translations": [ + { + "language": "ID", + "text": "Menyiapkan Bot Telegram di Superalgos", + "updated": 1616928254405 + } + ] }, { "style": "Text", - "text": "You will set up your bot in a backtesting session, so that you may easily test the announcements." + "text": "You will set up your bot in a backtesting session, so that you may easily test the announcements.", + "translations": [ + { + "language": "ID", + "text": "Kamu akan mensetup bot pada backtesting session, sehingga kamu lebih mudah dalam mengetest pengumuman.", + "updated": 1616928314869 + } + ] }, { "style": "List", "text": "1. Go to any of your backtesting sessions and add a Social Bot node using the session’s menu: A social bot will be added along with a telegram bot.", - "updated": 1611485546279 + "updated": 1611485546279, + "translations": [ + { + "language": "ID", + "text": "1. Pergi ke backtesting sessions dan tambahkan Social Bot node dari session’s menu: social bot akan ditambahkan bersama telegram bot.", + "updated": 1616928451125 + } + ] }, { "style": "List", "text": "2. Select Edit Telegram Bot on the telegram bot menu: Replace the placeholder text with the actual botToken and chatId you got earlier.", - "updated": 1611485581216 + "updated": 1611485581216, + "translations": [ + { + "language": "ID", + "text": "2. Pilih Edit Telegram Bot di telegram bot menu: Ubah placeholder text dengan aktual botToken dan chatId yang kamu dapatkan sebelumnya.", + "updated": 1616928506093 + } + ] }, { "style": "Text", - "text": "For example:" + "text": "For example:", + "translations": [ + { + "language": "ID", + "text": "Contohnya:", + "updated": 1616928514397 + } + ] }, { "style": "Json", @@ -128,19 +275,47 @@ }, { "style": "Text", - "text": "The system now has everything it needs to communicate with your Telegram bot." + "text": "The system now has everything it needs to communicate with your Telegram bot.", + "translations": [ + { + "language": "ID", + "text": "Sistem sekarang memiliki semua yang dibutuhkan untuk berkomunikasi dengan Telegram Bots milikmu.", + "updated": 1616928562420 + } + ] }, { "style": "Title", - "text": "Create Your Announcements" + "text": "Create Your Announcements", + "translations": [ + { + "language": "ID", + "text": "Membuat Pengumumanmu", + "updated": 1616928589846 + } + ] }, { "style": "Text", - "text": "You may create as many announcements as you wish, on any of the events listed in the Overview section above by clicking Add Announcement on the corresponding event node menu." + "text": "You may create as many announcements as you wish, on any of the events listed in the Overview section above by clicking Add Announcement on the corresponding event node menu.", + "translations": [ + { + "language": "ID", + "text": "Kamu akan membuat pengumuman sebanyak yang kamu mau, sesuai dengan event terdaftar pada Overview section diatas dengan mengclick Add Announcement di koresponden menu event node.", + "updated": 1616928711745 + } + ] }, { "style": "Text", - "text": "There are two different ways in which you may customize announcements:" + "text": "There are two different ways in which you may customize announcements:", + "translations": [ + { + "language": "ID", + "text": "Ada dua cara berbeda untuk mengkostumisasi pengumuman:", + "updated": 1616928734728 + } + ] }, { "style": "List", @@ -153,7 +328,14 @@ { "style": "Success", "text": "The Weak-hands buster strategy shipping with Superalgos features a complete set of announcements. Check them out and reuse them in your setup!", - "updated": 1611485640517 + "updated": 1611485640517, + "translations": [ + { + "language": "ID", + "text": "Strategi Weak-hands buster berkaitan dengan fitur Superalgos sebagai serangkaian lengkap dari pengumuman. Lihat mereka dan siapkan kembali di setup!", + "updated": 1616928883164 + } + ] }, { "style": "Title", @@ -161,11 +343,25 @@ }, { "style": "Text", - "text": "To set a plain text announcement, click Edit Announcement on the announcement node menu and set a message on the field text." + "text": "To set a plain text announcement, click Edit Announcement on the announcement node menu and set a message on the field text.", + "translations": [ + { + "language": "ID", + "text": "Untuk membuat pengumuman plain text, click Edit Announcement pada announcement node menu dan set pesan di tempat text.", + "updated": 1616928982224 + } + ] }, { "style": "Text", - "text": "For example:" + "text": "For example:", + "translations": [ + { + "language": "ID", + "text": "Contohnya:", + "updated": 1616928991922 + } + ] }, { "style": "Json", @@ -178,15 +374,36 @@ }, { "style": "Text", - "text": "To broadcast more elaborate messages that may include dynamic values of any of the current indicators or internal variables, set the message in the formula attached to the announcement instead." + "text": "To broadcast more elaborate messages that may include dynamic values of any of the current indicators or internal variables, set the message in the formula attached to the announcement instead.", + "translations": [ + { + "language": "ID", + "text": "Untuk membroadcast pesan yang lebih rumit yang mungkin menyertakan dynamic content dari salah satu indikator atau variabel internal, atur pesan dengan formula dibawah kedalam pengumuman.", + "updated": 1616929292467 + } + ] }, { "style": "Text", - "text": "The typical set up for a dynamic message consists of building a string by alternating “text between double quotes” with variables, separating them with plus signs (+)." + "text": "The typical set up for a dynamic message consists of building a string by alternating “text between double quotes” with variables, separating them with plus signs (+).", + "translations": [ + { + "language": "ID", + "text": "Penyiapan sederhana untuk pesan Dynamic terdiri dari pembuatan string dengan mengganti \"text diantara tanda kutip\" dengan variabel, dan memisahkannya dengan tanda tambah (+).", + "updated": 1616929904380 + } + ] }, { "style": "Text", - "text": "For example, a typical announcement formula for the take position event may look like this:" + "text": "For example, a typical announcement formula for the take position event may look like this:", + "translations": [ + { + "language": "ID", + "text": "Contohnya, formula pengumuman sederhana untuk ambil posisi pada suatu event.", + "updated": 1616929983820 + } + ] }, { "style": "Javascript", @@ -194,7 +411,14 @@ }, { "style": "Text", - "text": ".toFixed(0) rounds the number to zero decimal places. The above formula would result in something like:" + "text": ".toFixed(0) rounds the number to zero decimal places. The above formula would result in something like:", + "translations": [ + { + "language": "ID", + "text": ".toFixed(0) membulatkan angka ke tempat nol desimal. formula di atas akan menghasilkan sesuatu seperti:", + "updated": 1616930071150 + } + ] }, { "style": "Json", @@ -203,7 +427,14 @@ { "style": "Note", "text": "If your formula is valid, the system will ignore the plain text version you may have set up in the announcement configuration. If for any reason the formula results in an error, then the plain text version will be used.", - "updated": 1611485748590 + "updated": 1611485748590, + "translations": [ + { + "language": "ID", + "text": "Jika formulamu valid, Sistem akan mengabaikan versi plain text yang telah kamu atur untuk konfigurasi pengumuman. Jika dalam suatu keadaan formua menghasilkan error, maka versi plain text akan digunakan.", + "updated": 1616930177921 + } + ] }, { "style": "Title", @@ -211,23 +442,58 @@ }, { "style": "Text", - "text": "We mentioned earlier that, beyond setting announcements on events, you may also implement announcements at the level of a stop or take profit phase. These are useful to broadcast the management of dynamic stop and take profit targets." + "text": "We mentioned earlier that, beyond setting announcements on events, you may also implement announcements at the level of a stop or take profit phase. These are useful to broadcast the management of dynamic stop and take profit targets.", + "translations": [ + { + "language": "ID", + "text": "Kami telah jelaskan sebelumnya bahwa, selain menetapkan pengumuman dalam event, Kamu juga dapat menerapkan pengumuman pada level fase stop atau take profit, Hal ini berguna untuk membroadcast manajemen dari dynamic target stop dan target take profit.", + "updated": 1616930312081 + } + ] }, { "style": "Text", - "text": "When implemented at the level of a phase, the announcement is triggered every time the value of the underlying variable (the stop or take profit target) changes. This is an important difference, as the value may change at every candle (if you are using formulas that use variables)." + "text": "When implemented at the level of a phase, the announcement is triggered every time the value of the underlying variable (the stop or take profit target) changes. This is an important difference, as the value may change at every candle (if you are using formulas that use variables).", + "translations": [ + { + "language": "ID", + "text": "Ketika diterapkan pada level suatu fasem pengumuman akan memicu setiap kali nilai variable yang mendasari (target stop atau take profit) berubah. Hal ini adalah perbedaan penting, karena nilainya dapat berubah di setiap candle (jika kamu menggunakan formula yang menggunakan variabel).", + "updated": 1616930435548 + } + ] }, { "style": "Text", - "text": "This could result in too many announcements in relatively short intervals." + "text": "This could result in too many announcements in relatively short intervals.", + "translations": [ + { + "language": "ID", + "text": "Hal ini dapat mengakibatkan terlalu banyak pengumuman dalam interval yang relatif singkat.", + "updated": 1616930454433 + } + ] }, { "style": "Text", - "text": "The valueVariation parameter introduced in the announcement configuration may be used to filter out announcements until a certain threshold is achieved. The value you enter will set the percentage of variation that needs to occur before a new announcement is broadcasted." + "text": "The valueVariation parameter introduced in the announcement configuration may be used to filter out announcements until a certain threshold is achieved. The value you enter will set the percentage of variation that needs to occur before a new announcement is broadcasted.", + "translations": [ + { + "language": "ID", + "text": "mempengenalkan kedalam konfigurasi pengumuman untuk digunakan dalam memfilter pengumuman hingga ketreshold tertentu. Nilai yang kamu masukkan akan diatur dalam persentase variasi yang dibutuhkan sebelum pengumuman dibroadcast.", + "updated": 1616930623021 + } + ] }, { "style": "Text", - "text": "For instance, \"valueVariation\": 0.5 means a new announcement will be broadcasted every time the value of the underlying variable changes by 0.5%." + "text": "For instance, \"valueVariation\": 0.5 means a new announcement will be broadcasted every time the value of the underlying variable changes by 0.5%.", + "translations": [ + { + "language": "ID", + "text": "Contohnya, \"valueVariation\": 0.5 artinya pengumuman baru akan di broadcast setiap kali nilai dari dasar variabel berubah sebanyak 0.5%.", + "updated": 1616930700904 + } + ] }, { "style": "Json", @@ -236,53 +502,137 @@ }, { "style": "Title", - "text": "Finishing the Setup" + "text": "Finishing the Setup", + "translations": [ + { + "language": "ID", + "text": "Menyelesaikan Setup", + "updated": 1616930723890 + } + ] }, { "style": "Text", - "text": "It is unlikely that you will want to use the announcements feature from within a backtesting session. A more likely scenario is you will want to use it with a paper trading session (to generate signals) or from a live trading session, to monitor the activity of your live trading." + "text": "It is unlikely that you will want to use the announcements feature from within a backtesting session. A more likely scenario is you will want to use it with a paper trading session (to generate signals) or from a live trading session, to monitor the activity of your live trading.", + "translations": [ + { + "language": "ID", + "text": "Kemungkinan kecil kamu akan menggunakan fitur pengumuman dari backtesting session. Skenario yang lebih memungkinkan jika kamu ingin menggunakannya dengan paper trading session (Menggenerate sinyal) atau dari live trading session, untuk memonitor aktivitas dari live tradingmu.", + "updated": 1616930923555 + } + ] }, { "style": "Text", - "text": "All you need to do to finish your set up is detach the social bot node from the backtesting session and attach it to the session you wish to use it in. Make sure the corresponding tasks are stopped before detaching and attaching the social bot." + "text": "All you need to do to finish your set up is detach the social bot node from the backtesting session and attach it to the session you wish to use it in. Make sure the corresponding tasks are stopped before detaching and attaching the social bot.", + "translations": [ + { + "language": "ID", + "text": "Yang perlu kamu lakukan untuk menyelesaikan penyiapan ini adalah melepaskan social bot node dari backtesting session dan pasangkan kepada session yang kamu inginkan. Pastikan tasks yang berjalan sudah berhenti sebelum melepaskan dan memasangkan social bot.", + "updated": 1616931073057 + } + ] }, { "style": "Title", - "text": "Commercial Setups" + "text": "Commercial Setups", + "translations": [ + { + "language": "ID", + "text": "Setup untuk Komersial", + "updated": 1616931096555 + } + ] }, { "style": "Text", - "text": "If you are settting up a signals business or require a more complex setup to broadcast announcements from multiple sessions, multiple strategies, or even to multiple groups, the following considerations may help you decide how to move forwards." + "text": "If you are settting up a signals business or require a more complex setup to broadcast announcements from multiple sessions, multiple strategies, or even to multiple groups, the following considerations may help you decide how to move forwards.", + "translations": [ + { + "language": "ID", + "text": "Jika kamu sedang menyiapkan bisnis sinyal atau memerlukan penyiapan yang lebih kompleks untuk membroadcast pengumuman dari beberapa sessions, beberapa strategi, atau bahkan kebeberapa grup, Hal ini akan membantu mempertimbangkan keputusanmu untuk keberikutnya.", + "updated": 1616931205053 + } + ] }, { "style": "Important", "text": "Telegram does not allow running multiple instances of the same bot. Doing so may produce warnings, cause errors, delays in message delivery, lost messages, and erratic behavior in general.", - "updated": 1611485876079 + "updated": 1611485876079, + "translations": [ + { + "language": "ID", + "text": "Telegram tidak mengizinkan menjalankan banyak instance dari bot yang sama. Melakukan hal tersebut dapat menghasilkan peringatan, menyebabkan kesalahan, keterlambatan pengiriman pesan, pesan hilang, dan perilaku tidak menentu secara umum dari malfungsi bot.", + "updated": 1616931335441 + } + ] }, { "style": "Text", - "text": "The solution is quite simple. Set up multiple bots. The rule of thumb is you should use one bot for each trading session. Remember you can include as many bots as you wish in your Telegram groups. That is, you may have different bots broadcast from different sessions in the same group." + "text": "The solution is quite simple. Set up multiple bots. The rule of thumb is you should use one bot for each trading session. Remember you can include as many bots as you wish in your Telegram groups. That is, you may have different bots broadcast from different sessions in the same group.", + "translations": [ + { + "language": "ID", + "text": "Solusinya cukup mudah. Siapkan multiple bot. Aturan mainnya adalah kamu harus menggunakan satu untuk setiap sesi trading. Ingat kamu dapat memasukkan bot sebanyak kamu inginkan kedalam grup Telegrammu. Aritnya, kamu mungkin memiliki bot berbeda yang dibroadcast dari session berbeda dalam grup yang sama.", + "updated": 1616931501454 + } + ] }, { "style": "Success", "text": "If you wish to broadcast signals from multiple sessions to the same Telegram Group, you may name each bot in a way that each references their specific session, so that group members know exactly what each message is referring to.", - "updated": 1611485909076 + "updated": 1611485909076, + "translations": [ + { + "language": "ID", + "text": "Jika kamu ingin membroadcast sinyal dari beberapa session kedalam grup Telegram yang sama, kamu dapat menamai setiap bot dengan referesinya masing-masing terhadap spesifik session. Sehingga anggota grup tahu persis apa yang dirujuk setiap pesan.", + "updated": 1616931602612 + } + ] }, { "style": "Text", - "text": "For example, let’s say you are broadcasting signals from different markets… you may name your bots BTC/USDT, ETH/USDT and XMR/BTC." + "text": "For example, let’s say you are broadcasting signals from different markets… you may name your bots BTC/USDT, ETH/USDT and XMR/BTC.", + "translations": [ + { + "language": "ID", + "text": "Misalnya, kamu membroadcast sinyal dari market yang berbeda… Kamu dapat menamai bot dengan BTC / USDT, ETH / USDT, dan XMR / BTC.", + "updated": 1616931653602 + } + ] }, { "style": "Text", - "text": "Or maybe you have different strategies, then simply name the bots after each strategy." + "text": "Or maybe you have different strategies, then simply name the bots after each strategy.", + "translations": [ + { + "language": "ID", + "text": "Atau mungkin kamu memiliki strategi yang berbeda, maka cukup beri nama bot dengan setiap strategi.", + "updated": 1616931697879 + } + ] }, { "style": "Text", - "text": "This makes it really easy for group members to know what market or strategy the bot broadcasting the signal is referring to." + "text": "This makes it really easy for group members to know what market or strategy the bot broadcasting the signal is referring to.", + "translations": [ + { + "language": "ID", + "text": "Ini membuatnya sangat mudah bagi anggota grup untuk mengetahui market atau strategi apa yang dirujuk oleh bot yang membroadcast sinyal.", + "updated": 1616931728131 + } + ] }, { "style": "Text", - "text": "Another example… let’s say you are running a trading operation for friends and family. Each person is working with a different initial capital, different assets or different exchanges. in such case, you may set up multiple Telegram groups and multiple bots, so that each person may get precise information on what the bots are doing." + "text": "Another example… let’s say you are running a trading operation for friends and family. Each person is working with a different initial capital, different assets or different exchanges. in such case, you may set up multiple Telegram groups and multiple bots, so that each person may get precise information on what the bots are doing.", + "translations": [ + { + "language": "ID", + "text": "Contoh lain… misalkan kamu menjalankan trading operation untuk teman dan keluarga. Setiap orang bekerja dengan modal awal yang berbeda, aset yang berbeda, atau exchange yang berbeda. dalam kasus seperti itu, kamu dapat mengatur beberapa grup Telegram dan beberapa bot, sehingga setiap orang dapat memperoleh informasi yang tepat tentang apa yang dilakukan bot tersebut.", + "updated": 1616931801957 + } + ] } ] } \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-031-tutorial-step-careful-with-your-data.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-031-tutorial-step-careful-with-your-data.json index 09137ee5e..e1b94e1db 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-031-tutorial-step-careful-with-your-data.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-031-tutorial-step-careful-with-your-data.json @@ -14,6 +14,11 @@ "text": "Può volerci fino a un minuto perchè tutte le tasks si fermino. Il sistema non deve assolutamente essere chiuso prima che ciò accada.", "updated": 1614846504651, "style": "Definition" + }, + { + "language": "ID", + "text": "Membutuhkan hingga satu menit untuk semua tasks agar sampai berhenti. Jangan menutup sistem sebelum semua tasks berhenti.", + "updated": 1616932775779 } ] }, @@ -27,32 +32,72 @@ "text": "Dai un'occhiata alla console app per vedere come le tasks ricevono il segnale di stop!", "updated": 1614846474138, "style": "Callout" + }, + { + "language": "ID", + "text": "Periksa console app untuk melihat tasks berhenti!", + "updated": 1616932267740 } ], "updated": 1616416021973 }, { "style": "Text", - "text": "The proper way to close Superalgos is:" + "text": "The proper way to close Superalgos is:", + "translations": [ + { + "language": "ID", + "text": "Cara yang tepat untuk menutup Superalgos adalah:", + "updated": 1616932216490 + } + ] }, { "style": "List", "text": "Stop all tasks and allow a couple of minutes.", - "updated": 1616416090932 + "updated": 1616416090932, + "translations": [ + { + "language": "ID", + "text": "Matikan semua tasks dan tunggu beberapa menit.", + "updated": 1616932788679 + } + ] }, { "style": "List", "text": "When all tasks stop may you close the console app.", - "updated": 1616416111891 + "updated": 1616416111891, + "translations": [ + { + "language": "ID", + "text": "Setelah semua tasks berhenti kamu harus menutup console app.", + "updated": 1616932273154 + } + ] }, { "style": "List", - "text": "You may close the browser at any point and leave tasks processing in the background." + "text": "You may close the browser at any point and leave tasks processing in the background.", + "translations": [ + { + "language": "ID", + "text": "Kamu akan menutup browser dan membiarkan tasks memproses dilatar belakang.", + "updated": 1616932749614 + } + ] }, { "style": "Warning", "text": "Closing the Client before tasks stop may cause your data to become corrupt!", - "updated": 1616416130792 + "updated": 1616416130792, + "translations": [ + { + "language": "ID", + "text": "Menutup Client sebelum tasks berhenti akan menyebabkan data akan corrupt!", + "updated": 1616932378361 + } + ] } ] } \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-032-tutorial-step-the-bright-side.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-032-tutorial-step-the-bright-side.json index 87f273a22..331bcdd99 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-032-tutorial-step-the-bright-side.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-032-tutorial-step-the-bright-side.json @@ -14,6 +14,11 @@ "text": "Finora sei rimasto confinato nel lato oscuro di Superalgos. Preparati a incontrare il lato chiaro: il Charting Space.", "updated": 1614846601940, "style": "Definition" + }, + { + "language": "ID", + "text": "Sejauh ini, kamu telah selalu berada di sisi gelap dari Superalgos. Bersiaplah untuk terekspos di sisi terang: Charting Space.", + "updated": 1616932464702 } ] }, @@ -28,6 +33,11 @@ "text": "Il Charting Space si trova al di sopra del Design Space, separato da uno slider turchese. Come imparerai ad aspettarti da Superalgos, il Charting Space è configurabile e molto flessibile. Tutto ciò che accade al suo interno è definito nella gerarchia del Charting Space.", "updated": 1614846709741, "style": "Text" + }, + { + "language": "ID", + "text": "Charting Space tinggal diatas dari design space, terbagi atas turquoise slider. Seperti yang kamu ekspektasikan dari Superalgos, Charting Space sebuah konfigurasi dari fleksibilitas yang tinggi. Semua yang terjadi akan terlihat dari Charing Space.", + "updated": 1616932593483 } ] }, @@ -40,6 +50,11 @@ "text": "Il Charting Space può sbalordire al punto da far girare la testa. Non proseguire questo tutorial se sei sotto l'effetto di sostanze psicoattive.", "updated": 1614846855335, "style": "Warning" + }, + { + "language": "ID", + "text": "Charting Space digunakan untuk meledakkan kepalamu. Dimohon untuk berhenti dari tutorial ini jika kamu merasakan hal di bawah pengaruh zat psikoaktif.", + "updated": 1616932686549 } ], "updated": 1616416552336 diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-033-tutorial-step-break-on-through.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-033-tutorial-step-break-on-through.json index 09de4d89e..ade472c3f 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-033-tutorial-step-break-on-through.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-033-tutorial-step-break-on-through.json @@ -14,6 +14,11 @@ "text": "Ti insegnerò a muoverti e navigare nel Charting Space in un attimo...occupiamoci prima dello slider!", "updated": 1614846929188, "style": "Definition" + }, + { + "language": "ID", + "text": "Aku akan mempercepat gerakmu dalam berkeliling dan menelusuri charting space dengan cepat... Mari coba slider duluan!", + "updated": 1616932890422 } ] }, @@ -27,6 +32,11 @@ "text": "Clicca lo slider e trascinalo verso il basso per chiudere il design space e aprire lo charting space. Trascinalo verso l'alto per ottenere il risultato opposto. Per farlo con la tastiera, usa Ctrl + Shift + ↓. Prova anche con ↑ ← → !", "updated": 1614847060275, "style": "Callout" + }, + { + "language": "ID", + "text": "Click disana dan drag kebawah untuk menutup design space dan membuka charting space. Lakukan sebaliknya untuk bertukar posisi. Dari keyboard gunakan Ctrl + Shift + ↓. Coba juga ↑ ← →", + "updated": 1616932984437 } ] }, @@ -39,6 +49,11 @@ "text": "A meno che tu non abbia bisogno di tenere parzialmente aperti entrambi gli spazi, è sempre una buona idea chiudere del tutto uno dei due per non consumare troppe risorse sul tuo computer.", "updated": 1614847125222, "style": "Note" + }, + { + "language": "ID", + "text": "Kecuali jika kamu memerlukan kedua ruang untuk dibuka sebagian, sebaiknya tutup salah satunya untuk menghemat sumber daya komputasi di Perangkat-mu.", + "updated": 1616933049943 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-034-tutorial-step-navigating-the-white-room.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-034-tutorial-step-navigating-the-white-room.json index fe02f5d41..a92376679 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-034-tutorial-step-navigating-the-white-room.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-034-tutorial-step-navigating-the-white-room.json @@ -14,6 +14,11 @@ "text": "Proprio come il Design Space, il Charting Space ha un'enorme area dove puoi inserire grafici...tanti quanti il tuo hardware ne riesce a gestire!", "updated": 1614847190845, "style": "Definition" + }, + { + "language": "ID", + "text": "Seperti design space, fitur charting space area yang besar untuk mensetup chart... Sebanyak yang perangkatmu bisa!", + "updated": 1616933145394 } ] }, @@ -28,6 +33,11 @@ "text": "Ci sono solo due charts in questo Workspace Getting Started, per mantenere le cose semplici per i novellini. Utenti avanzati confrontano diversi grafici di diversi exchanges e diversi market.", "updated": 1614847284524, "style": "Text" + }, + { + "language": "ID", + "text": "Agar lebih mudah bagi para user baru, hanya ada dua charts di Getting Started Workspace. Pengguna lama dapat memonitor charts dari exchange dan market yang berbeda.", + "updated": 1616934950201 } ] }, @@ -40,6 +50,11 @@ "text": "Per muoverti nel Charting Space, clicca e trascina usando il tuo mouse. La combinazione di tasti è Shift più i tasti freccia ↑ ← → ↓", "updated": 1614847340001, "style": "Callout" + }, + { + "language": "ID", + "text": "Untuk bergerak sekeliling di charting space, click dan drag dengan mouse. Dengan keyboard dapat menggunakan Shift + ↑ ← → ↓", + "updated": 1616935011038 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-035-tutorial-step-talkin-time-travel.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-035-tutorial-step-talkin-time-travel.json index 853cccaf3..3cd62a8b2 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-035-tutorial-step-talkin-time-travel.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-035-tutorial-step-talkin-time-travel.json @@ -14,6 +14,11 @@ "text": "Poco fa ho detto che ci sono due grafici in questo workspace. In Superalgos, chiamiamo ognuno di questi grafici una Time Machine.", "updated": 1614847393489, "style": "Definition" + }, + { + "language": "ID", + "text": "Aku telah memberitahumu duluan ada dua charts di workspace ini. Dalam Superalgos, kam memanggilnya dengan Time Machine.", + "updated": 1616935192130 } ] }, @@ -27,6 +32,11 @@ "text": "Una Time Machine può contenere una o più Timeline Chart. Le chiamiamo così perchè tutti i Timeline Chart in una Time Machine sono sincronizzati nel tempo. Ciò permette di sovrapporre differenti livelli di dati che usano la stessa Time Scale.", "updated": 1614847651838, "style": "Text" + }, + { + "language": "ID", + "text": "Time machine akan menahan satu atau lebih Timeline Chart. Dalam time machines karena semua timeline charts dalam time machine tersingkronasi dengan waktu. Fitur time machines ini memungkinkan untuk menempatkan berbeda lapisan data dalam pembagian data di Time Scale yang sama.", + "updated": 1616935672320 } ] }, @@ -39,6 +49,11 @@ "text": "Sposta il puntatore del mouse sopra le Time Machine!", "updated": 1614847549742, "style": "Callout" + }, + { + "language": "ID", + "text": "Arahkan mouse pointer kearah time machines!", + "updated": 1616935491446 } ] }, @@ -52,6 +67,11 @@ "text": "Le label che spuntano da sinistra mostrano a quale exchange e market si riferiscono i dati. Una singola Time Machine può contenere dati da diversi markets e exchanges!", "updated": 1614847670664, "style": "Text" + }, + { + "language": "ID", + "text": "Perhatikan label yang ada dikiri yang menyatakan exchange dan market dari data yang diasosiasikan. Satu time machine akan dapat menyimpan dari berbagai market dan lebih dari satu exchange.", + "updated": 1616935697836 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-036-tutorial-step-bending-time.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-036-tutorial-step-bending-time.json index 4d57cf44b..e772c7664 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-036-tutorial-step-bending-time.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-036-tutorial-step-bending-time.json @@ -14,6 +14,11 @@ "text": "Ok...forse non è proprio come controllare il tempo, ma facciamo finta... Adorerai come puoi configurare le Time Machine in qualsiasi modo tu desideri.", "updated": 1614847760593, "style": "Definition" + }, + { + "language": "ID", + "text": "Oke ... mungkin sebenarnya tidak seperti mempelajari bending, tapi, bersabarlah ... Kamu akan menyukai bagaimana dapat membentuk time machine ke format apa pun yang di inginkan.", + "updated": 1616936357243 } ] }, @@ -27,6 +32,11 @@ "text": "Sposta il puntatore su uno qualsiasi dei lati della cornice turchese che definisce la Time Machine, e osserva cosa succede. Vedi come il lato si evidenzia in giallo?", "updated": 1614847838157, "style": "Text" + }, + { + "language": "ID", + "text": "Arahkan mouse pointermu ke salah satu tepi bingkai biru kehijauan yang menentukan time machine dan lihat apa yang terjadi. Lihat bagaimana tepi disorot dengan warna kuning?", + "updated": 1616936418748 } ] }, @@ -39,6 +49,11 @@ "text": "Forte! Ora cliccalo con il tasto sinistro e tira!", "updated": 1614847870184, "style": "Callout" + }, + { + "language": "ID", + "text": "Keren! Sekarang, click-kiri bingkai dan tarik!", + "updated": 1616936445152 } ] }, @@ -51,6 +66,11 @@ "text": "In questo modo puoi dare alle tue time machines la forma e aspetto che preferisci.", "updated": 1614847900032, "style": "Note" + }, + { + "language": "ID", + "text": "Beginilah cara kamu membentuk time machine sesuai keinginan Anda.", + "updated": 1616936472690 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-037-tutorial-step-size-matters.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-037-tutorial-step-size-matters.json index 63806604e..4d61df81f 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-037-tutorial-step-size-matters.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-037-tutorial-step-size-matters.json @@ -14,6 +14,11 @@ "text": "Che ne dici di adattare perfettamente la Time Machine al formato del tuo schermo?", "updated": 1614848136114, "style": "Definition" + }, + { + "language": "ID", + "text": "Bagaimana membuat time machine menjadi sesuai dengan aspect ratio dari layar?", + "updated": 1616936505798 } ] }, @@ -27,6 +32,11 @@ "text": "Dare alle tue time machines lo stesso aspect ratio del tuo schermo è importante perchè si adattino perfettamente ad esso.", "updated": 1614848156397, "style": "Text" + }, + { + "language": "ID", + "text": "Mencocokkan rasio aspek time machine kamu dengan rasio aspek laya sangat penting agar bagan pas dengan layarmu!", + "updated": 1616936545221 } ] }, @@ -40,6 +50,11 @@ "text": "Sposta il mouse su una delle time machines e premi Ctrl + Shift + Key-A. Fai lo stesso con l'altra.", "updated": 1614848104941, "style": "Callout" + }, + { + "language": "ID", + "text": "Point mousemu ke satu dari time machines dan tekan Ctrl + Shift + Key-A. Lakukan dengan yang satunya juga!", + "updated": 1616936593204 } ] }, @@ -53,6 +68,11 @@ "text": "D'ora in poi, lascia le due time machines con lo stesso aspect ratio del tuo schermo!", "updated": 1614848186502, "style": "Success" + }, + { + "language": "ID", + "text": "Biarkan dua time machine cocok dengan rasio aspek layarmu. dari sekarang!", + "updated": 1616936619368 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-038-tutorial-step-putting-things-in-order.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-038-tutorial-step-putting-things-in-order.json index e3b1d148e..c71f4b4f0 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-038-tutorial-step-putting-things-in-order.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-038-tutorial-step-putting-things-in-order.json @@ -14,6 +14,11 @@ "text": "Un'ultima cosa prima di tuffarci nei grafici. Devi sapere come tenere il tuo regno in ordine!", "updated": 1614848223577, "style": "Definition" + }, + { + "language": "ID", + "text": "Satu hal lagi sebelum kita lebih dalam ke charts. Kamu harus tahu bagaimana menata suatu tempat!", + "updated": 1616948198296 } ] }, @@ -27,6 +32,11 @@ "text": "Arriverà il momento in cui potresti dover lavorare con decine di grafici contemporaneamente. Sai già come modificare il loro formato, ma devi sapere come spostarli in modo da configurarli esattamente come vuoi tu. Tranquillo, è facile:", "updated": 1614848290495, "style": "Text" + }, + { + "language": "ID", + "text": "Waktunya akan tiba dimana kamu mungkin bekerja dengan puluhan chart. Kamu sudah tahu cara mengubah formatnya. Sekarang kamu perlu mempelajari cara memindahkannya sehingga bisa membuat pengaturan apa pun dibutuhkan. Cukup mudah dengan:", + "updated": 1616948323131 } ], "updated": 1616416902513 @@ -41,6 +51,11 @@ "text": "Premi Shift, clicca con il tasto sinistro e trascina!", "updated": 1614848320456, "style": "Callout" + }, + { + "language": "ID", + "text": "Tekan Shift, Click-kiri, dan drag!", + "updated": 1616948350330 } ] }, @@ -53,6 +68,11 @@ "text": "Bene, direi che abbiamo coperto tutto ciò che serve per configurare il Charting Space. È ora di tuffarci tra i grafici!", "updated": 1614848393942, "style": "Success" + }, + { + "language": "ID", + "text": "Aku yakin kita telah membahas segalanya tentang cara mengelola charting space. Saatnya menuju ke chart!", + "updated": 1616948406170 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-039-tutorial-step-get-in-the-wormhole.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-039-tutorial-step-get-in-the-wormhole.json index 94258d920..7a5f2e80b 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-039-tutorial-step-get-in-the-wormhole.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-039-tutorial-step-get-in-the-wormhole.json @@ -14,6 +14,11 @@ "text": "È il momento di tuffarci in una Time Machine e vedere che succede! Sei pronto per questa esperienza?", "updated": 1614892693632, "style": "Definition" + }, + { + "language": "ID", + "text": "Saatnya menuju Time Machine dan lihat yang terjadi! Apakah kamu siap untuk merasakan full-on immersive experience?", + "updated": 1616948557580 } ] }, @@ -27,6 +32,11 @@ "text": "Il Charting Space è un po'come il Google Maps dei grafici di mercato. Come sai già, si clicca e si trascina per spostarsi al suo interno...ma come si zoomma per vedere i dettagli?", "updated": 1614892771662, "style": "Text" + }, + { + "language": "ID", + "text": "Charting space seperti Google Maps untuk chart market. Seperti yang diketahui, kamu bisa click kiri dan drag untuk bergerak diarea landscape... Tapi, Bagaimana kamu memperbesar untuk melihat detailnya?", + "updated": 1616948680615 } ] }, @@ -39,6 +49,11 @@ "text": "Con la rotella del mouse! Provaci!", "updated": 1614892781701, "style": "Callout" + }, + { + "language": "ID", + "text": "Dengan mouse wheelmu! Cobalah!", + "updated": 1616948707864 } ] }, @@ -52,6 +67,11 @@ "text": "Esatto! Proprio come su Google Maps! Posiziona il mouse su un'area di interesse e gira la rotella in avanti per aumentare lo zoom, e all'indietro per diminuirlo!", "updated": 1614892836540, "style": "Text" + }, + { + "language": "ID", + "text": "Persis banget! Seperti Google Maps! Point mouse ke area yang diinginkan, lalu putar mouse wheelmu ke depan untuk memperbesar, dan ke belakang untuk memperkecil!", + "updated": 1616948793590 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-040-tutorial-step-the-elegant-way..json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-040-tutorial-step-the-elegant-way..json index 50cb1d131..c7ba357cf 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-040-tutorial-step-the-elegant-way..json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-040-tutorial-step-the-elegant-way..json @@ -14,6 +14,11 @@ "text": "Lo so, zoommare su un punto a caso difficilmente farà sì che il grafico si adatti al tuo schermo, vero? No problem...", "updated": 1614893061080, "style": "Definition" + }, + { + "language": "ID", + "text": "Aku tahu!, Memperbesar ke tempat acak tidak seperti langsung menuju ke kotak chart discreenmu, benar? Jangan khawatir... Coba trik ini!", + "updated": 1616948885540 } ], "updated": 1616417516192 @@ -22,11 +27,25 @@ { "style": "List", "text": "Adjust the aspect ratio: Point your mouse to the chart and hit Ctrl + Shift + Key-A", - "updated": 1616418151629 + "updated": 1616418151629, + "translations": [ + { + "language": "ID", + "text": "Menyesuaikan aspect ratio: Point mouse-mu ke chart dan tekan Ctrl + Shift + Key-A", + "updated": 1616948923519 + } + ] }, { "style": "List", - "text": "Zoom out: use the mouse wheel to go to the furthest zoom out position; only from this position will the next command work!" + "text": "Zoom out: use the mouse wheel to go to the furthest zoom out position; only from this position will the next command work!", + "translations": [ + { + "language": "ID", + "text": "Zoom out: gunakan mouse wheel untuk memposisikan zoom out terkecil; hanya dari posisi ini perintah berikutnya akan bekerja!", + "updated": 1616949119939 + } + ] }, { "style": "List", @@ -37,6 +56,11 @@ "text": "Fai doppio click sulla Time Machine in cima! Due volte!", "updated": 1614893194631, "style": "List" + }, + { + "language": "ID", + "text": "Double-click sekali: Ini memusatkan chart dan membawamu ke tingkat zoom tertentu; margin terlihat kekiri agar pas dengan nama dan tab chart di sudut kiri atas.", + "updated": 1616949208729 } ], "updated": 1616418234728 @@ -50,6 +74,11 @@ "text": "Il primo doppio click centra il grafico e lo zoomma, lasciando un po' di margine per mostrare il nome e la tab in alto a sinistra. Il secondo doppio-click ti trasporta al suo interno, al livello di zoom dove emergono i layer managers.", "updated": 1614893166373, "style": "List" + }, + { + "language": "ID", + "text": "Double-click lagi: Ini membawamu lebih jauh kedalam bagan, tingkat zoom ini secara sempurna cocok dengan layar beserta layer managers yang muncul.", + "updated": 1616949317416 } ], "updated": 1616418383322 diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-041-tutorial-step-moving-in-wonderland.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-041-tutorial-step-moving-in-wonderland.json index d5c1a2c9f..902ea672f 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-041-tutorial-step-moving-in-wonderland.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-041-tutorial-step-moving-in-wonderland.json @@ -14,6 +14,11 @@ "text": "Ecco, sei finalmente dentro un grafico. La prima cosa che vorrai fare sarà farci un giro e imparare cosa può fare per te.", "updated": 1614893263479, "style": "Definition" + }, + { + "language": "ID", + "text": "Akhirnya kamu berada didalam chart. Hal pertama yang harus dilakukan yaitu adalah berpindah-pindah dan mempelajari apa yang dapat dilakukan bagan ini untukmu.", + "updated": 1616949419191 } ] }, @@ -27,6 +32,11 @@ "text": "Facciamolo subito! Proprio come nel Design Space, puoi muoverti usando mouse e tastiera. Ecco come:", "updated": 1614893324158, "style": "Text" + }, + { + "language": "ID", + "text": "Mari menuju kesana! Seperti di design space—saat berada didalam time machine—kamu bergerak dengan menggunakan mouse dan keyboard. Begini caranya:", + "updated": 1616949477545 } ] }, @@ -39,6 +49,11 @@ "text": "Con il mouse, fai click con il tasto sinistro e trascina. Con la tastiera, usa le frecce: ← → ↑ ↓", "updated": 1614893357947, "style": "Callout" + }, + { + "language": "ID", + "text": "Dengan mouse, click-kiri dan drag. Dengan keyboard, gunakan panah: ← → ↑ ↓", + "updated": 1616949524257 } ] }, @@ -51,6 +66,11 @@ "text": "Come? Non funziona? Il grafico resta fermo? Proprio come nel video nel prossimo step? Ah, non preoccuparti! Lo so io cosa sta succedendo...", "updated": 1614893399468, "style": "Note" + }, + { + "language": "ID", + "text": "Apa? Tidak bekerja? Apa kamu tersangkut dengan chart yang ngefreeze? Step video distep berikutnya? Jangan khawatir! Aku tahu apa yang terjadi...", + "updated": 1616949623092 } ] } diff --git a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-042-tutorial-step-welcome-charts-scales-auto-locked.json b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-042-tutorial-step-welcome-charts-scales-auto-locked.json index 870f3666c..e1e9b3506 100644 --- a/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-042-tutorial-step-welcome-charts-scales-auto-locked.json +++ b/Projects/Superalgos/Schemas/Docs-Tutorials/welcome-to-superalgos-042-tutorial-step-welcome-charts-scales-auto-locked.json @@ -10,6 +10,11 @@ "text": "Questo step eseguirà un video in modalità schermo intero.", "updated": 1614893428433, "style": "Definition" + }, + { + "language": "ID", + "text": "Step ini akan menjalankan video mode layar penuh.", + "updated": 1616949686304 } ] }, diff --git a/Projects/Superalgos/TS/Task-Modules/FileStorage.js b/Projects/Superalgos/TS/Task-Modules/FileStorage.js index ac58e6395..737f7b61d 100644 --- a/Projects/Superalgos/TS/Task-Modules/FileStorage.js +++ b/Projects/Superalgos/TS/Task-Modules/FileStorage.js @@ -1,5 +1,6 @@ exports.newFileStorage = function newFileStorage(processIndex, host, port) { + const ip = require("ip"); const MODULE_NAME = 'FileStorage' const MAX_RETRY = 10 const FAST_RETRY_TIME_IN_MILISECONDS = 500 @@ -86,7 +87,7 @@ exports.newFileStorage = function newFileStorage(processIndex, host, port) { logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> fileLocation: ' + fileLocation) /* Here we actually reaad the file. */ - if (host === undefined || host === 'localhost') { + if (host === undefined || host === 'localhost' || host === ip.address() || host === '127.0.0.1') { /* We read the file from the local file system. */ const fs = require('fs') fs.readFile(fileLocation, onFileRead) @@ -158,7 +159,7 @@ exports.newFileStorage = function newFileStorage(processIndex, host, port) { if (canUsePrevious === true) { logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Could read the file, but could not parse it as it is not a valid JSON. Will try to read the PREVIOUS version instead. -> file = ' + fileLocation) - if (host === undefined || host === 'localhost') { + if (host === undefined || host === 'localhost' || host === ip.address() || host === '127.0.0.1') { /* We read the file from the local file system. */ const fs = require('fs') fs.readFile(fileLocation + '.Previous.json', onPreviousFileRead) diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.jscsrc b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.jscsrc new file mode 100644 index 000000000..dbaae2057 --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.jscsrc @@ -0,0 +1,46 @@ +{ + "disallowKeywordsOnNewLine": [ "else" ], + "disallowMixedSpacesAndTabs": true, + "disallowMultipleLineStrings": true, + "disallowMultipleVarDecl": true, + "disallowNewlineBeforeBlockStatements": true, + "disallowQuotedKeysInObjects": true, + "disallowSpaceAfterObjectKeys": true, + "disallowSpaceAfterPrefixUnaryOperators": true, + "disallowSpaceBeforePostfixUnaryOperators": true, + "disallowSpacesInCallExpression": true, + "disallowTrailingComma": true, + "disallowTrailingWhitespace": true, + "disallowYodaConditions": true, + + "requireCommaBeforeLineBreak": true, + "requireOperatorBeforeLineBreak": true, + "requireSpaceAfterBinaryOperators": true, + "requireSpaceAfterKeywords": [ "if", "for", "while", "else", "try", "catch" ], + "requireSpaceAfterLineComment": true, + "requireSpaceBeforeBinaryOperators": true, + "requireSpaceBeforeBlockStatements": true, + "requireSpaceBeforeKeywords": [ "else", "catch" ], + "requireSpaceBeforeObjectValues": true, + "requireSpaceBetweenArguments": true, + "requireSpacesInAnonymousFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInFunctionDeclaration": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInConditionalExpression": true, + "requireSpacesInForStatement": true, + "requireSpacesInsideArrayBrackets": "all", + "requireSpacesInsideObjectBrackets": "all", + "requireDotNotation": true, + + "maximumLineLength": 80, + "validateIndentation": 2, + "validateLineBreaks": "LF", + "validateParameterSeparator": ", ", + "validateQuoteMarks": "'" +} diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.jshintrc b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.jshintrc new file mode 100644 index 000000000..7e9739029 --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.jshintrc @@ -0,0 +1,89 @@ +{ + // JSHint Default Configuration File (as on JSHint website) + // See http://jshint.com/docs/ for more details + + "maxerr" : 50, // {int} Maximum error before stopping + + // Enforcing + "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.) + "camelcase" : false, // true: Identifiers must be in camelCase + "curly" : false, // true: Require {} for every new block or scope + "eqeqeq" : true, // true: Require triple equals (===) for comparison + "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() + "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. + "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` + "indent" : 2, // {int} Number of spaces to use for indentation + "latedef" : true, // true: Require variables/functions to be defined before being used + "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` + "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` + "noempty" : false, // true: Prohibit use of empty blocks + "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. + "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) + "plusplus" : false, // true: Prohibit use of `++` & `--` + "quotmark" : "single", // Quotation mark consistency: + // false : do nothing (default) + // true : ensure whatever is used is consistent + // "single" : require single quotes + // "double" : require double quotes + "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) + "unused" : true, // true: Require all defined variables be used + "strict" : true, // true: Requires all functions run in ES5 Strict Mode + "maxparams" : false, // {int} Max number of formal params allowed per function + "maxdepth" : 3, // {int} Max depth of nested blocks (within functions) + "maxstatements" : false, // {int} Max number statements per function + "maxcomplexity" : false, // {int} Max cyclomatic complexity per function + "maxlen" : false, // {int} Max number of characters per line + + // Relaxing + "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) + "boss" : false, // true: Tolerate assignments where comparisons would be expected + "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // true: Tolerate use of `== null` + "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) + "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) + "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) + // (ex: `for each`, multiple try/catch, function expression…) + "evil" : false, // true: Tolerate use of `eval` and `new Function()` + "expr" : false, // true: Tolerate `ExpressionStatement` as Programs + "funcscope" : false, // true: Tolerate defining variables inside control statements + "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') + "iterator" : false, // true: Tolerate using the `__iterator__` property + "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block + "laxbreak" : false, // true: Tolerate possibly unsafe line breakings + "laxcomma" : false, // true: Tolerate comma-first style coding + "loopfunc" : false, // true: Tolerate functions being defined in loops + "multistr" : false, // true: Tolerate multi-line strings + "noyield" : false, // true: Tolerate generator functions with no yield statement in them. + "notypeof" : false, // true: Tolerate invalid typeof operator values + "proto" : false, // true: Tolerate using the `__proto__` property + "scripturl" : false, // true: Tolerate script-targeted URLs + "shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` + "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation + "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` + "validthis" : false, // true: Tolerate using this in a non-constructor function + + // Environments + "browser" : true, // Web Browser (window, document, etc) + "browserify" : true, // Browserify (node.js code in the browser) + "couch" : false, // CouchDB + "devel" : true, // Development/debugging (alert, confirm, etc) + "dojo" : false, // Dojo Toolkit + "jasmine" : false, // Jasmine + "jquery" : false, // jQuery + "mocha" : true, // Mocha + "mootools" : false, // MooTools + "node" : true, // Node.js + "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) + "prototypejs" : false, // Prototype and Scriptaculous + "qunit" : false, // QUnit + "rhino" : false, // Rhino + "shelljs" : false, // ShellJS + "worker" : false, // Web Workers + "wsh" : false, // Windows Scripting Host + "yui" : false, // Yahoo User Interface + + // Custom Globals + "globals" : { + "module": true + } // additional predefined global variables +} diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.npmignore b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.npmignore new file mode 100644 index 000000000..1ca957177 --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.npmignore @@ -0,0 +1,2 @@ +node_modules/ +npm-debug.log diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.travis.yml b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.travis.yml new file mode 100644 index 000000000..a3a8fad6b --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/.travis.yml @@ -0,0 +1,15 @@ +sudo: false +language: node_js +node_js: + - "0.8" + - "0.10" + - "0.12" + - "4" + - "6" + +before_install: + - travis_retry npm install -g npm@2.14.5 + - travis_retry npm install + +script: + - npm test diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/README.md b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/README.md new file mode 100644 index 000000000..22e5819ff --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/README.md @@ -0,0 +1,90 @@ +# IP +[![](https://badge.fury.io/js/ip.svg)](https://www.npmjs.com/package/ip) + +IP address utilities for node.js + +## Installation + +### npm +```shell +npm install ip +``` + +### git + +```shell +git clone https://github.com/indutny/node-ip.git +``` + +## Usage +Get your ip address, compare ip addresses, validate ip addresses, etc. + +```js +var ip = require('ip'); + +ip.address() // my ip address +ip.isEqual('::1', '::0:1'); // true +ip.toBuffer('127.0.0.1') // Buffer([127, 0, 0, 1]) +ip.toString(new Buffer([127, 0, 0, 1])) // 127.0.0.1 +ip.fromPrefixLen(24) // 255.255.255.0 +ip.mask('192.168.1.134', '255.255.255.0') // 192.168.1.0 +ip.cidr('192.168.1.134/26') // 192.168.1.128 +ip.not('255.255.255.0') // 0.0.0.255 +ip.or('192.168.1.134', '0.0.0.255') // 192.168.1.255 +ip.isPrivate('127.0.0.1') // true +ip.isV4Format('127.0.0.1'); // true +ip.isV6Format('::ffff:127.0.0.1'); // true + +// operate on buffers in-place +var buf = new Buffer(128); +var offset = 64; +ip.toBuffer('127.0.0.1', buf, offset); // [127, 0, 0, 1] at offset 64 +ip.toString(buf, offset, 4); // '127.0.0.1' + +// subnet information +ip.subnet('192.168.1.134', '255.255.255.192') +// { networkAddress: '192.168.1.128', +// firstAddress: '192.168.1.129', +// lastAddress: '192.168.1.190', +// broadcastAddress: '192.168.1.191', +// subnetMask: '255.255.255.192', +// subnetMaskLength: 26, +// numHosts: 62, +// length: 64, +// contains: function(addr){...} } +ip.cidrSubnet('192.168.1.134/26') +// Same as previous. + +// range checking +ip.cidrSubnet('192.168.1.134/26').contains('192.168.1.190') // true + + +// ipv4 long conversion +ip.toLong('127.0.0.1'); // 2130706433 +ip.fromLong(2130706433); // '127.0.0.1' +``` + +### License + +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2012. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/lib/ip.js b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/lib/ip.js new file mode 100644 index 000000000..c1799a8c5 --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/lib/ip.js @@ -0,0 +1,416 @@ +'use strict'; + +var ip = exports; +var Buffer = require('buffer').Buffer; +var os = require('os'); + +ip.toBuffer = function(ip, buff, offset) { + offset = ~~offset; + + var result; + + if (this.isV4Format(ip)) { + result = buff || new Buffer(offset + 4); + ip.split(/\./g).map(function(byte) { + result[offset++] = parseInt(byte, 10) & 0xff; + }); + } else if (this.isV6Format(ip)) { + var sections = ip.split(':', 8); + + var i; + for (i = 0; i < sections.length; i++) { + var isv4 = this.isV4Format(sections[i]); + var v4Buffer; + + if (isv4) { + v4Buffer = this.toBuffer(sections[i]); + sections[i] = v4Buffer.slice(0, 2).toString('hex'); + } + + if (v4Buffer && ++i < 8) { + sections.splice(i, 0, v4Buffer.slice(2, 4).toString('hex')); + } + } + + if (sections[0] === '') { + while (sections.length < 8) sections.unshift('0'); + } else if (sections[sections.length - 1] === '') { + while (sections.length < 8) sections.push('0'); + } else if (sections.length < 8) { + for (i = 0; i < sections.length && sections[i] !== ''; i++); + var argv = [ i, 1 ]; + for (i = 9 - sections.length; i > 0; i--) { + argv.push('0'); + } + sections.splice.apply(sections, argv); + } + + result = buff || new Buffer(offset + 16); + for (i = 0; i < sections.length; i++) { + var word = parseInt(sections[i], 16); + result[offset++] = (word >> 8) & 0xff; + result[offset++] = word & 0xff; + } + } + + if (!result) { + throw Error('Invalid ip address: ' + ip); + } + + return result; +}; + +ip.toString = function(buff, offset, length) { + offset = ~~offset; + length = length || (buff.length - offset); + + var result = []; + if (length === 4) { + // IPv4 + for (var i = 0; i < length; i++) { + result.push(buff[offset + i]); + } + result = result.join('.'); + } else if (length === 16) { + // IPv6 + for (var i = 0; i < length; i += 2) { + result.push(buff.readUInt16BE(offset + i).toString(16)); + } + result = result.join(':'); + result = result.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3'); + result = result.replace(/:{3,4}/, '::'); + } + + return result; +}; + +var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/; +var ipv6Regex = + /^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i; + +ip.isV4Format = function(ip) { + return ipv4Regex.test(ip); +}; + +ip.isV6Format = function(ip) { + return ipv6Regex.test(ip); +}; +function _normalizeFamily(family) { + return family ? family.toLowerCase() : 'ipv4'; +} + +ip.fromPrefixLen = function(prefixlen, family) { + if (prefixlen > 32) { + family = 'ipv6'; + } else { + family = _normalizeFamily(family); + } + + var len = 4; + if (family === 'ipv6') { + len = 16; + } + var buff = new Buffer(len); + + for (var i = 0, n = buff.length; i < n; ++i) { + var bits = 8; + if (prefixlen < 8) { + bits = prefixlen; + } + prefixlen -= bits; + + buff[i] = ~(0xff >> bits) & 0xff; + } + + return ip.toString(buff); +}; + +ip.mask = function(addr, mask) { + addr = ip.toBuffer(addr); + mask = ip.toBuffer(mask); + + var result = new Buffer(Math.max(addr.length, mask.length)); + + var i = 0; + // Same protocol - do bitwise and + if (addr.length === mask.length) { + for (i = 0; i < addr.length; i++) { + result[i] = addr[i] & mask[i]; + } + } else if (mask.length === 4) { + // IPv6 address and IPv4 mask + // (Mask low bits) + for (i = 0; i < mask.length; i++) { + result[i] = addr[addr.length - 4 + i] & mask[i]; + } + } else { + // IPv6 mask and IPv4 addr + for (var i = 0; i < result.length - 6; i++) { + result[i] = 0; + } + + // ::ffff:ipv4 + result[10] = 0xff; + result[11] = 0xff; + for (i = 0; i < addr.length; i++) { + result[i + 12] = addr[i] & mask[i + 12]; + } + i = i + 12; + } + for (; i < result.length; i++) + result[i] = 0; + + return ip.toString(result); +}; + +ip.cidr = function(cidrString) { + var cidrParts = cidrString.split('/'); + + var addr = cidrParts[0]; + if (cidrParts.length !== 2) + throw new Error('invalid CIDR subnet: ' + addr); + + var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10)); + + return ip.mask(addr, mask); +}; + +ip.subnet = function(addr, mask) { + var networkAddress = ip.toLong(ip.mask(addr, mask)); + + // Calculate the mask's length. + var maskBuffer = ip.toBuffer(mask); + var maskLength = 0; + + for (var i = 0; i < maskBuffer.length; i++) { + if (maskBuffer[i] === 0xff) { + maskLength += 8; + } else { + var octet = maskBuffer[i] & 0xff; + while (octet) { + octet = (octet << 1) & 0xff; + maskLength++; + } + } + } + + var numberOfAddresses = Math.pow(2, 32 - maskLength); + + return { + networkAddress: ip.fromLong(networkAddress), + firstAddress: numberOfAddresses <= 2 ? + ip.fromLong(networkAddress) : + ip.fromLong(networkAddress + 1), + lastAddress: numberOfAddresses <= 2 ? + ip.fromLong(networkAddress + numberOfAddresses - 1) : + ip.fromLong(networkAddress + numberOfAddresses - 2), + broadcastAddress: ip.fromLong(networkAddress + numberOfAddresses - 1), + subnetMask: mask, + subnetMaskLength: maskLength, + numHosts: numberOfAddresses <= 2 ? + numberOfAddresses : numberOfAddresses - 2, + length: numberOfAddresses, + contains: function(other) { + return networkAddress === ip.toLong(ip.mask(other, mask)); + } + }; +}; + +ip.cidrSubnet = function(cidrString) { + var cidrParts = cidrString.split('/'); + + var addr = cidrParts[0]; + if (cidrParts.length !== 2) + throw new Error('invalid CIDR subnet: ' + addr); + + var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10)); + + return ip.subnet(addr, mask); +}; + +ip.not = function(addr) { + var buff = ip.toBuffer(addr); + for (var i = 0; i < buff.length; i++) { + buff[i] = 0xff ^ buff[i]; + } + return ip.toString(buff); +}; + +ip.or = function(a, b) { + a = ip.toBuffer(a); + b = ip.toBuffer(b); + + // same protocol + if (a.length === b.length) { + for (var i = 0; i < a.length; ++i) { + a[i] |= b[i]; + } + return ip.toString(a); + + // mixed protocols + } else { + var buff = a; + var other = b; + if (b.length > a.length) { + buff = b; + other = a; + } + + var offset = buff.length - other.length; + for (var i = offset; i < buff.length; ++i) { + buff[i] |= other[i - offset]; + } + + return ip.toString(buff); + } +}; + +ip.isEqual = function(a, b) { + a = ip.toBuffer(a); + b = ip.toBuffer(b); + + // Same protocol + if (a.length === b.length) { + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return false; + } + return true; + } + + // Swap + if (b.length === 4) { + var t = b; + b = a; + a = t; + } + + // a - IPv4, b - IPv6 + for (var i = 0; i < 10; i++) { + if (b[i] !== 0) return false; + } + + var word = b.readUInt16BE(10); + if (word !== 0 && word !== 0xffff) return false; + + for (var i = 0; i < 4; i++) { + if (a[i] !== b[i + 12]) return false; + } + + return true; +}; + +ip.isPrivate = function(addr) { + return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i + .test(addr) || + /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i + .test(addr) || + /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || + /^f[cd][0-9a-f]{2}:/i.test(addr) || + /^fe80:/i.test(addr) || + /^::1$/.test(addr) || + /^::$/.test(addr); +}; + +ip.isPublic = function(addr) { + return !ip.isPrivate(addr); +}; + +ip.isLoopback = function(addr) { + return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/ + .test(addr) || + /^fe80::1$/.test(addr) || + /^::1$/.test(addr) || + /^::$/.test(addr); +}; + +ip.loopback = function(family) { + // + // Default to `ipv4` + // + family = _normalizeFamily(family); + + if (family !== 'ipv4' && family !== 'ipv6') { + throw new Error('family must be ipv4 or ipv6'); + } + + return family === 'ipv4' ? '127.0.0.1' : 'fe80::1'; +}; + +// +// ### function address (name, family) +// #### @name {string|'public'|'private'} **Optional** Name or security +// of the network interface. +// #### @family {ipv4|ipv6} **Optional** IP family of the address (defaults +// to ipv4). +// +// Returns the address for the network interface on the current system with +// the specified `name`: +// * String: First `family` address of the interface. +// If not found see `undefined`. +// * 'public': the first public ip address of family. +// * 'private': the first private ip address of family. +// * undefined: First address with `ipv4` or loopback address `127.0.0.1`. +// +ip.address = function(name, family) { + var interfaces = os.networkInterfaces(); + var all; + + // + // Default to `ipv4` + // + family = _normalizeFamily(family); + + // + // If a specific network interface has been named, + // return the address. + // + if (name && name !== 'private' && name !== 'public') { + var res = interfaces[name].filter(function(details) { + var itemFamily = details.family.toLowerCase(); + return itemFamily === family; + }); + if (res.length === 0) + return undefined; + return res[0].address; + } + + var all = Object.keys(interfaces).map(function (nic) { + // + // Note: name will only be `public` or `private` + // when this is called. + // + var addresses = interfaces[nic].filter(function (details) { + details.family = details.family.toLowerCase(); + if (details.family !== family || ip.isLoopback(details.address)) { + return false; + } else if (!name) { + return true; + } + + return name === 'public' ? ip.isPrivate(details.address) : + ip.isPublic(details.address); + }); + + return addresses.length ? addresses[0].address : undefined; + }).filter(Boolean); + + return !all.length ? ip.loopback(family) : all[0]; +}; + +ip.toLong = function(ip) { + var ipl = 0; + ip.split('.').forEach(function(octet) { + ipl <<= 8; + ipl += parseInt(octet); + }); + return(ipl >>> 0); +}; + +ip.fromLong = function(ipl) { + return ((ipl >>> 24) + '.' + + (ipl >> 16 & 255) + '.' + + (ipl >> 8 & 255) + '.' + + (ipl & 255) ); +}; diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/package.json b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/package.json new file mode 100644 index 000000000..3ad47f64e --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/package.json @@ -0,0 +1,54 @@ +{ + "_from": "ip", + "_id": "ip@1.1.5", + "_inBundle": false, + "_integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "_location": "/ip", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "ip", + "name": "ip", + "escapedName": "ip", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "_shasum": "bdded70114290828c0a039e72ef25f5aaec4354a", + "_spec": "ip", + "_where": "/home/superalgos/Live/Superalgos/Projects/Superalgos/TS/Task-Modules", + "author": { + "name": "Fedor Indutny", + "email": "fedor@indutny.com" + }, + "bugs": { + "url": "https://github.com/indutny/node-ip/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "[![](https://badge.fury.io/js/ip.svg)](https://www.npmjs.com/package/ip)", + "devDependencies": { + "jscs": "^2.1.1", + "jshint": "^2.8.0", + "mocha": "~1.3.2" + }, + "homepage": "https://github.com/indutny/node-ip", + "license": "MIT", + "main": "lib/ip", + "name": "ip", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/indutny/node-ip.git" + }, + "scripts": { + "fix": "jscs lib/*.js test/*.js --fix", + "test": "jscs lib/*.js test/*.js && jshint lib/*.js && mocha --reporter spec test/*-test.js" + }, + "version": "1.1.5" +} diff --git a/Projects/Superalgos/TS/Task-Modules/node_modules/ip/test/api-test.js b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/test/api-test.js new file mode 100644 index 000000000..2e390f986 --- /dev/null +++ b/Projects/Superalgos/TS/Task-Modules/node_modules/ip/test/api-test.js @@ -0,0 +1,407 @@ +'use strict'; + +var ip = require('..'); +var assert = require('assert'); +var net = require('net'); +var os = require('os'); + +describe('IP library for node.js', function() { + describe('toBuffer()/toString() methods', function() { + it('should convert to buffer IPv4 address', function() { + var buf = ip.toBuffer('127.0.0.1'); + assert.equal(buf.toString('hex'), '7f000001'); + assert.equal(ip.toString(buf), '127.0.0.1'); + }); + + it('should convert to buffer IPv4 address in-place', function() { + var buf = new Buffer(128); + var offset = 64; + ip.toBuffer('127.0.0.1', buf, offset); + assert.equal(buf.toString('hex', offset, offset + 4), '7f000001'); + assert.equal(ip.toString(buf, offset, 4), '127.0.0.1'); + }); + + it('should convert to buffer IPv6 address', function() { + var buf = ip.toBuffer('::1'); + assert(/(00){15,15}01/.test(buf.toString('hex'))); + assert.equal(ip.toString(buf), '::1'); + assert.equal(ip.toString(ip.toBuffer('1::')), '1::'); + assert.equal(ip.toString(ip.toBuffer('abcd::dcba')), 'abcd::dcba'); + }); + + it('should convert to buffer IPv6 address in-place', function() { + var buf = new Buffer(128); + var offset = 64; + ip.toBuffer('::1', buf, offset); + assert(/(00){15,15}01/.test(buf.toString('hex', offset, offset + 16))); + assert.equal(ip.toString(buf, offset, 16), '::1'); + assert.equal(ip.toString(ip.toBuffer('1::', buf, offset), + offset, 16), '1::'); + assert.equal(ip.toString(ip.toBuffer('abcd::dcba', buf, offset), + offset, 16), 'abcd::dcba'); + }); + + it('should convert to buffer IPv6 mapped IPv4 address', function() { + var buf = ip.toBuffer('::ffff:127.0.0.1'); + assert.equal(buf.toString('hex'), '00000000000000000000ffff7f000001'); + assert.equal(ip.toString(buf), '::ffff:7f00:1'); + + buf = ip.toBuffer('ffff::127.0.0.1'); + assert.equal(buf.toString('hex'), 'ffff000000000000000000007f000001'); + assert.equal(ip.toString(buf), 'ffff::7f00:1'); + + buf = ip.toBuffer('0:0:0:0:0:ffff:127.0.0.1'); + assert.equal(buf.toString('hex'), '00000000000000000000ffff7f000001'); + assert.equal(ip.toString(buf), '::ffff:7f00:1'); + }); + }); + + describe('fromPrefixLen() method', function() { + it('should create IPv4 mask', function() { + assert.equal(ip.fromPrefixLen(24), '255.255.255.0'); + }); + it('should create IPv6 mask', function() { + assert.equal(ip.fromPrefixLen(64), 'ffff:ffff:ffff:ffff::'); + }); + it('should create IPv6 mask explicitly', function() { + assert.equal(ip.fromPrefixLen(24, 'IPV6'), 'ffff:ff00::'); + }); + }); + + describe('not() method', function() { + it('should reverse bits in address', function() { + assert.equal(ip.not('255.255.255.0'), '0.0.0.255'); + }); + }); + + describe('or() method', function() { + it('should or bits in ipv4 addresses', function() { + assert.equal(ip.or('0.0.0.255', '192.168.1.10'), '192.168.1.255'); + }); + it('should or bits in ipv6 addresses', function() { + assert.equal(ip.or('::ff', '::abcd:dcba:abcd:dcba'), + '::abcd:dcba:abcd:dcff'); + }); + it('should or bits in mixed addresses', function() { + assert.equal(ip.or('0.0.0.255', '::abcd:dcba:abcd:dcba'), + '::abcd:dcba:abcd:dcff'); + }); + }); + + describe('mask() method', function() { + it('should mask bits in address', function() { + assert.equal(ip.mask('192.168.1.134', '255.255.255.0'), '192.168.1.0'); + assert.equal(ip.mask('192.168.1.134', '::ffff:ff00'), '::ffff:c0a8:100'); + }); + + it('should not leak data', function() { + for (var i = 0; i < 10; i++) + assert.equal(ip.mask('::1', '0.0.0.0'), '::'); + }); + }); + + describe('subnet() method', function() { + // Test cases calculated with http://www.subnet-calculator.com/ + var ipv4Subnet = ip.subnet('192.168.1.134', '255.255.255.192'); + + it('should compute ipv4 network address', function() { + assert.equal(ipv4Subnet.networkAddress, '192.168.1.128'); + }); + + it('should compute ipv4 network\'s first address', function() { + assert.equal(ipv4Subnet.firstAddress, '192.168.1.129'); + }); + + it('should compute ipv4 network\'s last address', function() { + assert.equal(ipv4Subnet.lastAddress, '192.168.1.190'); + }); + + it('should compute ipv4 broadcast address', function() { + assert.equal(ipv4Subnet.broadcastAddress, '192.168.1.191'); + }); + + it('should compute ipv4 subnet number of addresses', function() { + assert.equal(ipv4Subnet.length, 64); + }); + + it('should compute ipv4 subnet number of addressable hosts', function() { + assert.equal(ipv4Subnet.numHosts, 62); + }); + + it('should compute ipv4 subnet mask', function() { + assert.equal(ipv4Subnet.subnetMask, '255.255.255.192'); + }); + + it('should compute ipv4 subnet mask\'s length', function() { + assert.equal(ipv4Subnet.subnetMaskLength, 26); + }); + + it('should know whether a subnet contains an address', function() { + assert.equal(ipv4Subnet.contains('192.168.1.180'), true); + }); + + it('should know whether a subnet does not contain an address', function() { + assert.equal(ipv4Subnet.contains('192.168.1.195'), false); + }); + }); + + describe('subnet() method with mask length 32', function() { + // Test cases calculated with http://www.subnet-calculator.com/ + var ipv4Subnet = ip.subnet('192.168.1.134', '255.255.255.255'); + it('should compute ipv4 network\'s first address', function() { + assert.equal(ipv4Subnet.firstAddress, '192.168.1.134'); + }); + + it('should compute ipv4 network\'s last address', function() { + assert.equal(ipv4Subnet.lastAddress, '192.168.1.134'); + }); + + it('should compute ipv4 subnet number of addressable hosts', function() { + assert.equal(ipv4Subnet.numHosts, 1); + }); + }); + + describe('subnet() method with mask length 31', function() { + // Test cases calculated with http://www.subnet-calculator.com/ + var ipv4Subnet = ip.subnet('192.168.1.134', '255.255.255.254'); + it('should compute ipv4 network\'s first address', function() { + assert.equal(ipv4Subnet.firstAddress, '192.168.1.134'); + }); + + it('should compute ipv4 network\'s last address', function() { + assert.equal(ipv4Subnet.lastAddress, '192.168.1.135'); + }); + + it('should compute ipv4 subnet number of addressable hosts', function() { + assert.equal(ipv4Subnet.numHosts, 2); + }); + }); + + describe('cidrSubnet() method', function() { + // Test cases calculated with http://www.subnet-calculator.com/ + var ipv4Subnet = ip.cidrSubnet('192.168.1.134/26'); + + it('should compute an ipv4 network address', function() { + assert.equal(ipv4Subnet.networkAddress, '192.168.1.128'); + }); + + it('should compute an ipv4 network\'s first address', function() { + assert.equal(ipv4Subnet.firstAddress, '192.168.1.129'); + }); + + it('should compute an ipv4 network\'s last address', function() { + assert.equal(ipv4Subnet.lastAddress, '192.168.1.190'); + }); + + it('should compute an ipv4 broadcast address', function() { + assert.equal(ipv4Subnet.broadcastAddress, '192.168.1.191'); + }); + + it('should compute an ipv4 subnet number of addresses', function() { + assert.equal(ipv4Subnet.length, 64); + }); + + it('should compute an ipv4 subnet number of addressable hosts', function() { + assert.equal(ipv4Subnet.numHosts, 62); + }); + + it('should compute an ipv4 subnet mask', function() { + assert.equal(ipv4Subnet.subnetMask, '255.255.255.192'); + }); + + it('should compute an ipv4 subnet mask\'s length', function() { + assert.equal(ipv4Subnet.subnetMaskLength, 26); + }); + + it('should know whether a subnet contains an address', function() { + assert.equal(ipv4Subnet.contains('192.168.1.180'), true); + }); + + it('should know whether a subnet contains an address', function() { + assert.equal(ipv4Subnet.contains('192.168.1.195'), false); + }); + + }); + + describe('cidr() method', function() { + it('should mask address in CIDR notation', function() { + assert.equal(ip.cidr('192.168.1.134/26'), '192.168.1.128'); + assert.equal(ip.cidr('2607:f0d0:1002:51::4/56'), '2607:f0d0:1002::'); + }); + }); + + describe('isEqual() method', function() { + it('should check if addresses are equal', function() { + assert(ip.isEqual('127.0.0.1', '::7f00:1')); + assert(!ip.isEqual('127.0.0.1', '::7f00:2')); + assert(ip.isEqual('127.0.0.1', '::ffff:7f00:1')); + assert(!ip.isEqual('127.0.0.1', '::ffaf:7f00:1')); + assert(ip.isEqual('::ffff:127.0.0.1', '::ffff:127.0.0.1')); + assert(ip.isEqual('::ffff:127.0.0.1', '127.0.0.1')); + }); + }); + + + describe('isPrivate() method', function() { + it('should check if an address is localhost', function() { + assert.equal(ip.isPrivate('127.0.0.1'), true); + }); + + it('should check if an address is from a 192.168.x.x network', function() { + assert.equal(ip.isPrivate('192.168.0.123'), true); + assert.equal(ip.isPrivate('192.168.122.123'), true); + assert.equal(ip.isPrivate('192.162.1.2'), false); + }); + + it('should check if an address is from a 172.16.x.x network', function() { + assert.equal(ip.isPrivate('172.16.0.5'), true); + assert.equal(ip.isPrivate('172.16.123.254'), true); + assert.equal(ip.isPrivate('171.16.0.5'), false); + assert.equal(ip.isPrivate('172.25.232.15'), true); + assert.equal(ip.isPrivate('172.15.0.5'), false); + assert.equal(ip.isPrivate('172.32.0.5'), false); + }); + + it('should check if an address is from a 169.254.x.x network', function() { + assert.equal(ip.isPrivate('169.254.2.3'), true); + assert.equal(ip.isPrivate('169.254.221.9'), true); + assert.equal(ip.isPrivate('168.254.2.3'), false); + }); + + it('should check if an address is from a 10.x.x.x network', function() { + assert.equal(ip.isPrivate('10.0.2.3'), true); + assert.equal(ip.isPrivate('10.1.23.45'), true); + assert.equal(ip.isPrivate('12.1.2.3'), false); + }); + + it('should check if an address is from a private IPv6 network', function() { + assert.equal(ip.isPrivate('fd12:3456:789a:1::1'), true); + assert.equal(ip.isPrivate('fe80::f2de:f1ff:fe3f:307e'), true); + assert.equal(ip.isPrivate('::ffff:10.100.1.42'), true); + assert.equal(ip.isPrivate('::FFFF:172.16.200.1'), true); + assert.equal(ip.isPrivate('::ffff:192.168.0.1'), true); + }); + + it('should check if an address is from the internet', function() { + assert.equal(ip.isPrivate('165.225.132.33'), false); // joyent.com + }); + + it('should check if an address is a loopback IPv6 address', function() { + assert.equal(ip.isPrivate('::'), true); + assert.equal(ip.isPrivate('::1'), true); + assert.equal(ip.isPrivate('fe80::1'), true); + }); + }); + + describe('loopback() method', function() { + describe('undefined', function() { + it('should respond with 127.0.0.1', function() { + assert.equal(ip.loopback(), '127.0.0.1') + }); + }); + + describe('ipv4', function() { + it('should respond with 127.0.0.1', function() { + assert.equal(ip.loopback('ipv4'), '127.0.0.1') + }); + }); + + describe('ipv6', function() { + it('should respond with fe80::1', function() { + assert.equal(ip.loopback('ipv6'), 'fe80::1') + }); + }); + }); + + describe('isLoopback() method', function() { + describe('127.0.0.1', function() { + it('should respond with true', function() { + assert.ok(ip.isLoopback('127.0.0.1')) + }); + }); + + describe('127.8.8.8', function () { + it('should respond with true', function () { + assert.ok(ip.isLoopback('127.8.8.8')) + }); + }); + + describe('8.8.8.8', function () { + it('should respond with false', function () { + assert.equal(ip.isLoopback('8.8.8.8'), false); + }); + }); + + describe('fe80::1', function() { + it('should respond with true', function() { + assert.ok(ip.isLoopback('fe80::1')) + }); + }); + + describe('::1', function() { + it('should respond with true', function() { + assert.ok(ip.isLoopback('::1')) + }); + }); + + describe('::', function() { + it('should respond with true', function() { + assert.ok(ip.isLoopback('::')) + }); + }); + }); + + describe('address() method', function() { + describe('undefined', function() { + it('should respond with a private ip', function() { + assert.ok(ip.isPrivate(ip.address())); + }); + }); + + describe('private', function() { + [ undefined, 'ipv4', 'ipv6' ].forEach(function(family) { + describe(family, function() { + it('should respond with a private ip', function() { + assert.ok(ip.isPrivate(ip.address('private', family))); + }); + }); + }); + }); + + var interfaces = os.networkInterfaces(); + + Object.keys(interfaces).forEach(function(nic) { + describe(nic, function() { + [ undefined, 'ipv4' ].forEach(function(family) { + describe(family, function() { + it('should respond with an ipv4 address', function() { + var addr = ip.address(nic, family); + assert.ok(!addr || net.isIPv4(addr)); + }); + }); + }); + + describe('ipv6', function() { + it('should respond with an ipv6 address', function() { + var addr = ip.address(nic, 'ipv6'); + assert.ok(!addr || net.isIPv6(addr)); + }); + }) + }); + }); + }); + + describe('toLong() method', function() { + it('should respond with a int', function() { + assert.equal(ip.toLong('127.0.0.1'), 2130706433); + assert.equal(ip.toLong('255.255.255.255'), 4294967295); + }); + }); + + describe('fromLong() method', function() { + it('should repond with ipv4 address', function() { + assert.equal(ip.fromLong(2130706433), '127.0.0.1'); + assert.equal(ip.fromLong(4294967295), '255.255.255.255'); + }); + }) +}); diff --git a/Projects/Superalgos/TS/Task-Modules/package-lock.json b/Projects/Superalgos/TS/Task-Modules/package-lock.json index 68a719117..788ece015 100644 --- a/Projects/Superalgos/TS/Task-Modules/package-lock.json +++ b/Projects/Superalgos/TS/Task-Modules/package-lock.json @@ -2,6 +2,11 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "ws": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",