I18n.translations = { en: { phone_title: 'Send Phone Number', phone_description: 'Find friends using your number', phone_placeholder: 'Phone number', confirm_description: 'Confirmation code', confirm_validation_title: 'Confirmation code', confirm_validation_description: 'Wrong format', password_description: 'Password', password_placeholder: 'Type your password', password_placeholder2: 'Confirm', password_error: 'Password should be not less then 6 symbols.', password_error1: 'Password confirmation doesn\'t match password.', password_validation_title: 'Password', faucet_incorrect_title: 'Incorrect faucet', faucet_incorrect_description: 'Please, select a one from the list', debug_mode_title: 'Debug mode', debug_mode_description: 'Starts/stops a debug mode', faucet_title: 'Faucet', faucet_description: 'Get some ETH', faucet_placeholder: 'Faucet URL' }, ru: { phone_title: 'Отправить номер телефона', phone_description: 'Найти друзей, используя ваш номер', phone_placeholder: 'Номер телефона', confirm_description: 'Код подтверждения', confirm_validation_title: 'Код подтверждения', confirm_validation_description: 'Неверный формат', password_description: 'Пароль', password_placeholder: 'Введите свой пароль', password_placeholder2: 'Повторно введите пароль для подтверждения', password_error: 'Пароль должен содержать не менее 6 символов', password_error1: 'Подтверждение пароля не совпадает с паролем', password_validation_title: 'Пароль' }, af: { phone_title: 'Stuur telefoonnommer', phone_description: 'Vind vriende deur jou nommer te gebruik', phone_placeholder: 'Telefoonnommer', confirm_description: 'Bevestigingskode', confirm_validation_title: 'Bevestigingskode', confirm_validation_description: 'Verkeerde formaat', password_description: 'Wagwoord', password_placeholder: 'Tik jou wagwoord in', password_placeholder2: 'Tik asseblief weer jou wagwoord in om te bevestig', password_error: 'Wagwoord mag nie minder as 6 simbole wees nie.', password_error1: 'Wagwoordbevestiging is nie dieselfde as wagwoord nie.', password_validation_title: 'Wagwoord' }, ar: { phone_title: 'أرسل رقم الهاتف', phone_description: 'ابحث عن الأصدقاء باستخدام رقمك', phone_placeholder: 'رقم الهاتف', confirm_description: 'رمز التأكيد', confirm_validation_title: 'رمز التأكيد', confirm_validation_description: 'صيغة خاطئة', password_description: 'كلمة المرور', password_placeholder: 'اكتب كلمة المرور الخاصة بك', password_placeholder2: 'الرجاء إعادة إدخال كلمة المرور للتأكيد', password_error: 'ينبغي أن لا تقل كلمة المرور عن 6 رموز.', password_error1: 'لا يتوافق تأكيد كلمة المرور مع كلمة المرور.', password_validation_title: 'كلمة المرور' }, 'zh-hant': { phone_title: '發送手機號碼', phone_description: '使用您的號碼發現好友', phone_placeholder: '手機號碼', confirm_description: '確認碼', confirm_validation_title: '確認碼', confirm_validation_description: '格式錯誤', password_description: '密碼', password_placeholder: '鍵入您的密碼', password_placeholder2: '重新鍵入您的密碼', password_error: '密碼不得短於6個字元。', password_error1: '確認密碼與鍵入的密碼不一致。', password_validation_title: '密碼' }, 'zh-hans': { phone_title: '发送电话号码', phone_description: '用你的号码来查找朋友', phone_placeholder: '电话号码', confirm_description: '确认码', confirm_validation_title: '确认码', confirm_validation_description: '格式错误', password_description: '密码', password_placeholder: '输入密码', password_placeholder2: '请重新输入密码以确认', password_error: '密码应不少于6个字符。', password_error1: '密码确认信息与密码不匹配。', password_validation_title: '密码' }, 'zh-yue': { phone_title: '發送電話號碼', phone_description: '使用本電話號碼查找好友', phone_placeholder: '電話號碼', confirm_description: '驗證碼', confirm_validation_title: '驗證碼', confirm_validation_description: '格式錯誤', password_description: '密碼', password_placeholder: '輸入密碼', password_placeholder2: '請重新輸入密碼確認', password_error: '密碼不能短於6個字符.', password_error1: '確認密碼與輸入密碼不符.', password_validation_title: '密碼' }, 'zh-wuu': { phone_title: '发送电话号码', phone_description: '用您的号码查找朋友', phone_placeholder: '电话号码', confirm_description: '确认码', confirm_validation_title: '确认码', confirm_validation_description: '错误格式', password_description: '密码', password_placeholder: '输入密码', password_placeholder2: '请重新输入密码确认', password_error: '密码应不小于6个字符。', password_error1: '密码确认不匹配。', password_validation_title: '密码' }, nl: { phone_title: 'Stuur telefoonnummer', phone_description: 'Zoek vrienden met behulp van je nummer', phone_placeholder: 'Telefoonnummer', confirm_description: 'Bevestigingscode', confirm_validation_title: 'Bevestigingscode', confirm_validation_description: 'Verkeerd format', password_description: 'Wachtwoord', password_placeholder: 'Typ je wachtwoord', password_placeholder2: 'Voer je wachtwoord opnieuw in om te bevestigen', password_error: 'Wachtwoord moet minstens 6 tekens hebben.', password_error1: 'Wachtwoordbevestiging komt niet overeen met wachtwoord.', password_validation_title: 'Wachtwoord' }, fr: { phone_title: 'Envoyer le numéro de téléphone', phone_description: 'Trouver des amis en utilisant votre numéro', phone_placeholder: 'Numéro de téléphone', confirm_description: 'Code de confirmation', confirm_validation_title: 'Code de confirmation', confirm_validation_description: 'Format incorrect', password_description: 'Mot de passe', password_placeholder: 'Tapez votre mot de passe', password_placeholder2: 'Veuillez retapez votre mot de passe pour le confirmer', password_error: 'Le mot de passe doit contenir 6 symboles au minimum.', password_error1: 'Le mot de passe de confirmation ne correspond pas au mot de passe.', password_validation_title: 'Mot de passe' }, de: { phone_title: 'Telefonnummer absenden', phone_description: 'Freunde mit Ihrer Nummer finden', phone_placeholder: 'Telefonnummer', confirm_description: 'Bestätigungscode', confirm_validation_title: 'Bestätigungscode', confirm_validation_description: 'Falsches Format', password_description: 'Passwort', password_placeholder: 'Geben Sie Ihr Passwort ein', password_placeholder2: 'Bitte geben Sie das Passwort zur Bestätigung erneut ein', password_error: 'Das Passwort sollte nicht weniger als 6 Stellen beinhalten', password_error1: 'Die Passwortbestätigung stimmt nicht mit dem Passwort überein', password_validation_title: 'Passwort', }, hi: { phone_title: 'फ़ोन नंबर भेजें', phone_description: 'अपने नंबर का उपयोग करके दोस्त ढूंढें', phone_placeholder: 'फ़ोन नंबर', confirm_description: 'पुष्टि कोड', confirm_validation_title: 'पुष्टि कोड', confirm_validation_description: 'गलत प्रारूप', password_description: 'पासवर्ड', password_placeholder: 'अपना पासवर्ड टाइप करें', password_placeholder2: 'पुष्टि करने के लिए फिर से पासवर्ड दर्ज करें', password_error: 'पासवर्ड 6 प्रतीकों से कम का नहीं होना चाहिए।', password_error1: 'पासवर्ड पुष्टि पासवर्ड मेल नहीं खाता है।', password_validation_title: 'पासवर्ड' }, hu: { phone_title: 'Telefonszám küldése', phone_description: 'Ismerősök megkeresése telefonszám alapján', phone_placeholder: 'Telefonszám', confirm_description: 'Megerősítési kód', confirm_validation_title: 'Megerősítési kód', confirm_validation_description: 'Rossz formátum', password_description: 'Jelszó', password_placeholder: 'Add meg a jelszavad', password_placeholder2: 'A megerősítéshez kérjük, add meg újra a jelszavad', password_error: 'A jelszó nem lehet hosszabb 6 szimbólumnál.', password_error1: 'A megerősített jelszó nem egyezik a jelszóval.', password_validation_title: 'Jelszó' }, it: { phone_title: 'Invia numero di telefono', phone_description: 'Trova gli amici che usano il tuo numero', phone_placeholder: 'Numero di telefono', confirm_description: 'Codice di conferma', confirm_validation_title: 'Codice di conferma', confirm_validation_description: 'Formato errato', password_description: 'Password', password_placeholder: 'Digita la tua password', password_placeholder2: 'Reinserisci la password per confermare', password_error: 'La password deve contenere almeno 6 caratteri.', password_error1: 'Conferma password\ la password non corrisponde.', password_validation_title: 'Password' }, ja: { phone_title: '電話番号を送信', phone_description: 'あなたの番号を使用している友人を検索', phone_placeholder: '携帯電話番号', confirm_description: '確認コード', confirm_validation_title: '確認コード', confirm_validation_description: '間違った形式', password_description: 'パスワード', password_placeholder: 'パスワードを入力してください', password_placeholder2: '確認のためにパスワードを再入力してください', password_error: 'パスワードは6文字以下でなければなりません.', password_error1: 'パスワードの確認がパスワードと一致しません。', password_validation_title: 'パスワード' }, ko: { phone_title: '전화번호 보내기', phone_description: '내 번호를 사용하여 친구 찾기', phone_placeholder: '전화번호', confirm_description: '확인 코드', confirm_validation_title: '확인 코드', confirm_validation_description: '잘못된 형식', password_description: '비밀번호', password_placeholder: '비밀번호를 입력하세요', password_placeholder2: '확인을 위해 비밀번호를 다시 입력해 주세요', password_error: '비밀번호는 6자 이상이어야 합니다.', password_error1: '확인용 비밀번호가 원래 비밀번호와 일치하지 않습니다.', password_validation_title: '비밀번호' }, pl: { phone_title: 'Wyślij numer telefonu', phone_description: 'Znajdź znajomych, używając swojego numeru', phone_placeholder: 'Numer telefonu', confirm_description: 'Kod potwierdzający', confirm_validation_title: 'Kod potwierdzający', confirm_validation_description: 'Nieprawidłowy format', password_description: 'Hasło', password_placeholder: 'Wpisz swoje hasło', password_placeholder2: 'Wprowadź ponownie hasło, aby potwierdzić', password_error: 'Hasło powinno zawierać co najmniej 6 symboli.', password_error1: 'Wprowadzone i potwierdzone hasła nie są takie same.', password_validation_title: 'Hasło' }, 'pt-br': { phone_title: 'Enviar número de telefone', phone_description: 'Encontrar amigos por meio do seu número', phone_placeholder: 'Número de telefone', confirm_description: 'Código de confirmação', confirm_validation_title: 'Código de confirmação', confirm_validation_description: 'Formato incorreto', password_description: 'Senha', password_placeholder: 'Digite sua senha', password_placeholder2: 'Por favor, digite a senha novamente para confirmar', password_error: 'A senha deve ter no mínimo 6 símbolos.', password_error1: 'A confirmação da senha é diferente da senha.', password_validation_title: 'Senha' }, 'pt-pt': { phone_title: 'Enviar o Número de Telefone', phone_description: 'Encontrar amigos que utilizem o seu número', phone_placeholder: 'Número de telefone', confirm_description: 'Código de confirmação', confirm_validation_title: 'Código de confirmação', confirm_validation_description: 'Formato errado', password_description: 'Palavra-passe', password_placeholder: 'Digite a sua palavra-passe', password_placeholder2: 'Por favor, volte a digitar a palavra-passe para confirmar', password_error: 'A palavra-passe não deve ter menos de 6 símbolos.', password_error1: 'A confirmação da palavra-passe não coincide com a palavra-passe.', password_validation_title: 'Palavra-passe' }, ro: { phone_title: 'Trimite numărul de telefon', phone_description: 'Găsește prieteni folosindu-ți numărul de telefon', phone_placeholder: 'Număr de telefon', confirm_description: 'Cod de confirmare', confirm_validation_title: 'Cod de confirmare', confirm_validation_description: 'Format greșit', password_description: 'Parolă', password_placeholder: 'Tastează parola', password_placeholder2: 'Te rugăm să re-introduci parola pentru a confirma', password_error: 'Parola trebuie să aibă cel puțin 6 simboluri.', password_error1: 'Parola confirmată nu este aceeași cu parola introdusă.', password_validation_title: 'Parolă' }, sl: { phone_title: 'Pošlji telefonsko številko', phone_description: 'Iskanje prijateljev z uporabo tvoje telefonske številke', phone_placeholder: 'Telefonska številka', confirm_description: 'Potrditvena koda', confirm_validation_title: 'Potrditvena koda', confirm_validation_description: 'Neveljaven format', password_description: 'Geslo', password_placeholder: 'Vnesi svoje geslo', password_placeholder2: 'Prosimo, ponovno vnesi geslo za potrditev', password_error: 'Geslo mora vsebovati vsaj 6 simbolov.', password_error1: 'Potrditev gesla se ne ujema z geslom.', password_validation_title: 'Geslo' }, es: { phone_title: 'Enviar número de teléfono', phone_description: 'Encontrar amigos que estén utilizando tu número', phone_placeholder: 'Número de teléfono', confirm_description: 'Código de confirmación', confirm_validation_title: 'Código de confirmación', confirm_validation_description: 'Formato erróneo', password_description: 'Contraseña', password_placeholder: 'Escribe tu contraseña', password_placeholder2: 'Por favor, vuelve a escribir la contraseña para confirmar', password_error: 'La contraseña no debe ser inferior a 6 símbolos.', password_error1: 'La confirmación de contraseña no coincide con la contraseña.', password_validation_title: 'Contraseña' }, 'es-ar': { phone_title: 'Envia un número telefónico', phone_description: 'Encuentra amigos utilizando tu número', phone_placeholder: 'Número telefónico', confirm_description: 'Código de confirmación', confirm_validation_title: 'Código de confirmación', confirm_validation_description: 'Formato incorrecto', password_description: 'Contraseña', password_placeholder: 'Ingresa tu contraseña', password_placeholder2: 'Ingresa tu contraseña para confirmar', password_error: 'Las contraseñas deben contener no menos de 6 símbolos.', password_error1: 'La confirmación de la contraseña no coincide con la contraseña.', password_validation_title: 'Contraseña' }, sw: { phone_title: 'Tuma Namba ya Simu', phone_description: 'Pata marafiki kwa kutumia namba yako', phone_placeholder: 'Namba ya simu', confirm_description: 'Kificho cha uthibitisho', confirm_validation_title: 'Kificho cha uthibitisho', confirm_validation_description: 'Muundo hafifu', password_description: 'Nenosiri', password_placeholder: 'Andika nenosiri lako', password_placeholder2: 'Tafadhali ingiza tena nenosiri kuthibitisha', password_error: 'Nenosiri lisiwe chini ya alama 6.', password_error1: 'Uthibitisho wa nenosiri haulingani na nenosiri.', password_validation_title: 'Nenosiri' }, sv: { phone_title: 'Skicka telefonnummer', phone_description: 'Hitta vänner som använder ditt nummer', phone_placeholder: 'Telefonnummer', confirm_description: 'Bekräftelsekod', confirm_validation_title: 'Bekräftelsekod', confirm_validation_description: 'Fel format', password_description: 'Lösenord', password_placeholder: 'Skriv ditt lösenord', password_placeholder2: 'Var god ange ditt lösenord igen för att bekräfta', password_error: 'Lösenordet bör inte vara mindre än 6 symboler.', password_error1: 'Lösenordsbekräftelsen matcharinte lösenordet.', password_validation_title: 'Lösenord' }, 'fr-ch': { phone_title: 'Envoyer numéro de téléphone', phone_description: 'Trouvez des amis en utilisant votre numéro', phone_placeholder: 'Numéro de téléphone', confirm_description: 'Code de confirmation', confirm_validation_title: 'Code de confirmation', confirm_validation_description: 'Mauvais format', password_description: 'Mot de passe', password_placeholder: 'Tapez votre mot de passe', password_placeholder2: 'Veuillez saisir à nouveau le mot de passe pour confirmer', password_error: 'Le mot de passe doit avoir au moins 6 caractères.', password_error1: 'La confirmation du mot de passe ne correspond pas au premier mot de passe.', password_validation_title: 'Mot de passe' }, 'de-ch': { phone_title: 'Sende Telefonnummer', phone_description: 'Finde Freunde mittels deiner Telefonnummer', phone_placeholder: 'Telefonnummer', confirm_description: 'Konfirmationscode', confirm_validation_title: 'Konfirmationscode', confirm_validation_description: 'Falsches Format', password_description: 'Passwort', password_placeholder: 'Gib dein Passwort ein', password_placeholder2: 'Bitte gib das Passwort zur Bestätigung erneut ein', password_error: 'Passwort sollte nicht kleiner als 6 Symbole sein.', password_error1: 'Passwort Bestätigung stimmt mit Passwort nicht überein.', password_validation_title: 'Passwort' }, 'it-ch': { phone_title: 'Invia numero di telefono', phone_description: 'Trova amici che utilizzano il tuo numero', phone_placeholder: 'Numero di telefono', confirm_description: 'Codice di conferma', confirm_validation_title: 'Codice di conferma', confirm_validation_description: 'Formato errato', password_description: 'Password', password_placeholder: 'Digita la tua password', password_placeholder2: 'Inserisci nuovamente la password per confermare', password_error: 'La password non può contenere meno di 6 caratteri.', password_error1: 'La password di conferma non corrisponde alla password.', password_validation_title: 'Password' }, th: { phone_title: 'ส่งหมายเลขโทรศัพท์', phone_description: 'ค้นหาเพื่อนโดยใช้หมายเลขของคุณ ', phone_placeholder: 'หมายเลขโทรศัพท์', confirm_description: 'รหัสยืนยัน', confirm_validation_title: 'รหัสยืนยัน', confirm_validation_description: 'รูปแบบผิด', password_description: 'รหัสผ่าน', password_placeholder: 'พิมพ์รหัสผ่านของคุณ', password_placeholder2: 'โปรดกรอกรหัสผ่านอีกครั้งเพื่อยืนยัน', password_error: 'รหัสผ่านควรมีสัญลักษณ์ไม่น้อยกว่า 6 ตัว', password_error1: 'การยืนยันรหัสผ่านไม่ตรงกับรหัสผ่าน', password_validation_title: 'รหัสผ่าน' }, tr: { phone_title: 'Telefon Numarasını Gönder', phone_description: 'Telefon numaranı kullanarak arkadaşlarınızı bulun', phone_placeholder: 'Telefon numarası', confirm_description: 'Onay kodu', confirm_validation_title: 'Onay kodu', confirm_validation_description: 'Hatalı format', password_description: 'Şifre', password_placeholder: 'Şifrenizi girin', password_placeholder2: 'Onaylamak için lütfen parolanızı yeniden girin', password_error: 'Şifre 6 simgeden daha kısa olmamalıdır.', password_error1: 'Şifre onayı, şifre ile eşleşmiyor.', password_validation_title: 'Şifre' }, uk: { phone_title: 'Надіслати номер телефону', phone_description: 'Знайдіть друзів, використовуючи свій номер', phone_placeholder: 'Номер телефону', confirm_description: 'Код підтвердження', confirm_validation_title: 'Код підтвердження', confirm_validation_description: 'Неправильний формат', password_description: 'Пароль', password_placeholder: 'Введіть свій пароль', password_placeholder2: 'Будь ласка, введіть пароль ще раз для підтвердження', password_error: 'Пароль повинен бути не менше 6 символів.', password_error1: 'Підтвердження паролю не співпадає з паролем.', password_validation_title: 'Пароль' }, ur: { phone_title: 'فون نمبر بھیجیں', phone_description: 'فون نمبر استعمال کرتے ہوئے دوستوں کو تلاش کریں', phone_placeholder: 'فون نمبر', confirm_description: 'تصدیقی کوڈ', confirm_validation_title: 'تصدیقی کوڈ', confirm_validation_description: 'غلط فارمیٹ', password_description: 'پاسورڈ', password_placeholder: 'اپنا پاسورڈ لکھیں', password_placeholder2: 'برائے مہربانی تصدیق کے لیے اپنا پاسورڈ دوبارہ لکھیں', password_error: 'پاسورڈ 6 اعداد سے چھوٹا نہیں ہونا چاہیے۔', password_error1: 'تصدیقی پاسورڈ پاسورڈ سے مماثل نہیں', password_validation_title: 'پاسورڈ' }, vi: { phone_title: 'Gửi số điện thoại', phone_description: 'Tìm bạn bè bằng các sử dụng số điện thoại của bạn', phone_placeholder: 'Số điện thoại', confirm_description: 'Mã xác nhận', confirm_validation_title: 'Mã xác nhận', confirm_validation_description: 'Sai định dạng', password_description: 'Mật khẩu', password_placeholder: 'Gõ mật khẩu của bạn', password_placeholder2: 'Vui lòng nhập lại mật khẩu để xác nhận', password_error: 'Mật khẩu không được ít hơn 6 ký tự.', password_error1: 'Xác nhận mật khẩu không khớp với mật khẩu.', password_validation_title: 'Mật khẩu' } }; var WEB3_UNIT = [ 'kwei/ada', 'mwei/babbage', 'gwei/shannon', 'szabo', 'finney', 'ether', 'kether/grand/einstein', 'mether', 'gether', 'tether' ]; // because web3 doesn't provide params or docs var DOC_MAP = { console: { log: { desc: 'Outputs a message to chat context.', args: [{ name: 'text', type: 'String', desc: 'message to output to chat context' }] } }, web3: { // setProvider : ['provider'], // TODO version: { api: { desc: 'The ethereum js api version.' }, node: { desc: 'The client/node version.' }, network: { desc: 'The network protocol version.' }, ethereum: { desc: 'The ethereum protocol version.' }, whisper: { desc: 'The whisper protocol version.' }, }, isConnected: { desc: 'Check if a connection to a node exists.', args: [] }, currentProvider: { desc: 'Will contain the current provider, if one is set. This can be used to check if mist etc. set already a provider.' }, reset: { desc: 'Should be called to reset state of web3. Resets everything except manager. Uninstalls all filters. Stops polling.', args: [{ name: 'keepIsSyncing', type: 'Boolean', desc: 'If true it will uninstall all filters, but will keep the web3.eth.isSyncing() polls' }] }, sha3: { desc: 'Returns the Keccak-256 SHA3 of the given data.', args: [{ name: 'string', type: 'String', desc: 'The string to hash using the Keccak-256 SHA3 algorithm' }, { name: 'options', type: 'Object', optional: true, desc: 'Set encoding to hex if the string to hash is encoded in hex. A leading 0x will be automatically ignored.' }] }, toHex: { desc: 'Converts any value into HEX', args: [{ name: 'mixed', type: 'String|Number|Object|Array|BigNumber', desc: 'The value to parse to HEX. If its an object or array it will be JSON.stringify first. If its a BigNumber it will make it the HEX value of a number.' }] }, toAscii: { desc: 'Converts a HEX string into a ASCII string.', args: [{ name: 'hexString', type: 'String', desc: 'A HEX string to be converted to ascii.' }] }, fromAscii: { desc: 'Converts any ASCII string to a HEX string.', args: [{ name: 'string', type: 'String', desc: 'An ASCII string to be converted to HEX.' }, { name: 'padding', type: 'Number', desc: 'The number of bytes the returned HEX string should have. ' }] }, toDecimal: { desc: 'Converts a HEX string to its number representation.', args: [{ name: 'hexString', type: 'String', desc: 'An HEX string to be converted to a number.' }] }, fromDecimal: { desc: 'Converts a number or number string to its HEX representation.', args: [{ name: 'number', type: 'Number', desc: 'A number to be converted to a HEX string.' }] }, fromWei: { desc: 'Converts a number of wei into an ethereum unit', args: [{ name: 'number', type: 'Number|String|BigNumber', desc: 'A number or BigNumber instance.' }, { name: 'unit', type: 'string', desc: 'One of the ether units' }] }, toWei: { desc: 'Converts an ethereum unit into wei', args: [{ name: 'number', type: 'Number|String|BigNumber', desc: 'A number or BigNumber instance.' }, { name: 'unit', type: 'string', desc: 'One of the ether units' }] }, toBigNumber: { desc: 'Converts a given number into a BigNumber instance', args: [{ name: 'numberOrHexString', type: 'Number|String', desc: 'A number, number string or HEX string of a number.' }] }, net: { listening: { desc: 'Is node actively listening for network connections?' }, peerCount: { desc: 'Returns the number of connected peers' } }, isAddress: { desc: '', args: [{ name: '', type: 'string', desc: 'hex string' }], // TODO not in docs }, eth: { defaultAccount: { desc: 'The currently set default address' }, defaultBlock: { desc: 'The default block number to use when querying a state.' }, syncing: { desc: 'Returns the either a sync object, when the node is syncing or false.' }, isSyncing: { desc: 'This convenience function calls the callback everytime a sync starts, updates and stops.', args: [{ name: 'callback', type: 'Function', desc: 'The callback will be fired with true when the syncing starts and with false when it stopped. While syncing it will return the syncing object: {startingBlock, currentBlock, highestBlock}' }] }, coinbase: { desc: 'Returns the coinbase address were the mining rewards go to.' }, mining: { desc: 'Says whether the node is mining or not.' }, hashrate: { desc: 'Returns the number of hashes per second that the node is mining with.' }, gasPrice: { desc: 'Returns the current gas price. The gas price is determined by the x latest blocks median gas price' }, accounts: { desc: 'Returns a list of accounts the node controls' }, blockNumber: { desc: 'Returns the current block number' }, getBalance: { desc: 'Get the balance of an address at a given block.', args: [{ name: 'addressHexString', type: 'String', desc: 'The address to get the balance of' }, { name: 'defaultBlock', type: 'Number|String', optional: true, desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getStorageAt: { desc: 'Get the storage at a specific position of an address.', args: [{ name: 'addressHexString', type: 'String', desc: 'The address to get the storage from.' }, { name: 'position', type: 'Number', desc: 'The index position of the storage.' }, { name: 'defaultBlock', type: 'Number|String', optional: true, desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getCode: { desc: 'Get the code at a specific address.', args: [{ name: 'addressHexString', type: 'String', desc: 'The address to get the code from.' }, { name: 'defaultBlock', type: 'Number|String', optional: true, desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getBlock: { desc: 'Returns a block matching the block number or block hash.', args: [{ name: 'blockHashOrBlockNumber', type: 'String|Number', desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"' }, { name: 'returnTransactionObjects', type: 'Boolean', optional: true, desc: '(default false) If true, the returned block will contain all transactions as objects, if false it will only contains the transaction hashes.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getBlockTransactionCount: { desc: 'Returns the number of transaction in a given block.', args: [{ name: 'hashStringOrBlockNumber', type: 'String|Number', desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getUncle: { desc: 'Returns a blocks uncle by a given uncle index position', args: [{ name: 'blockHashStringOrNumber', type: 'String|Number', desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"' }, { name: 'uncleNumber', type: 'Number', desc: 'The index position of the uncle.' }, { name: 'returnTransactionObjects', type: 'Boolean', desc: '(default false) If true, the returned block will contain all transactions as objects, if false it will only contains the transaction hashes.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getBlockUncleCount: { desc: '', // TODO missing from docs }, getTransaction: { desc: 'Returns a transaction matching the given transaction hash.', args: [{ name: 'transactionHash', type: 'String', desc: 'The transaction hash.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getTransactionFromBlock: { desc: 'Returns a transaction based on a block hash or number and the transactions index position.', args: [{ name: 'hashStringOrBlockNumber', type: 'String|Number', desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"' }, { name: 'indexNumber', type: 'Number', desc: 'The transactions index position.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getTransactionReceipt: { desc: 'Returns the receipt of a transaction by transaction hash.', args: [{ name: 'hashString', type: 'String', desc: 'The transaction hash.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, getTransactionCount: { desc: 'Get the numbers of transactions sent from this address.', args: [{ name: 'addressHexString', type: 'String', desc: 'The address to get the numbers of transactions from.' }, { name: 'defaultBlock', type: 'String|Number', desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, sendTransaction: { desc: 'Sends a transaction to the network.', args: [{ name: 'transactionObject', type: 'Object', desc: 'The transaction object to send: {from[, to][, value][, gas][, gasPrice][, data][, nonce]}' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, sendRawTransaction: { desc: 'Sends an already signed transaction.', args: [{ name: 'signedTransactionData', type: 'String', desc: 'Signed transaction data in HEX format' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, sign: { desc: 'Signs data from a specific account. This account needs to be unlocked.', args: [{ name: 'address', type: 'String', desc: 'Address to sign with.' }, { name: 'dataToSign', type: 'String', desc: 'Data to sign.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, call: { desc: 'Executes a message call transaction, which is directly executed in the VM of the node, but never mined into the blockchain.', args: [{ name: 'callObject', type: 'String', desc: 'Address to sign with.' }, { name: 'defaultBlock', type: 'String', optional: true, desc: 'Data to sign.' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, estimateGas: { desc: 'Executes a message call or transaction, which is directly executed in the VM of the node, but never mined into the blockchain and returns the amount of the gas used.', args: [{ name: 'callObject', type: 'Object', desc: 'The transaction object to send: {[from][, to][, value][, gas][, gasPrice][, data][, nonce]}' }, { name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, filter: { // TODO: add description desc: '', args: [{ name: 'options', type: 'String|Object', desc: 'The string "latest" or "pending" to watch for changes in the latest block or pending transactions respectively. Or a filter options object as follows: {fromBlock: Number|String, toBlock: Number|String, address: String, topics: StringArray}' }, { name: 'callback', type: 'Function', optional: true, desc: 'Watch callback' }] }, // TODO filters // watch : ['callback'], // stopWatching : ['callback'], contract: { desc: 'Creates a contract object for a solidity contract, which can be used to initiate contracts on an address.', args: [{ name: 'abiArray', type: 'Array', desc: 'ABI array with descriptions of functions and events of the contract.' }] }, getCompilers: { desc: 'Gets a list of available compilers.', args: [{ name: 'callback', type: 'Function', optional: true, desc: 'If you pass a callback the HTTP request is made asynchronous.' }] }, compile: { // TODO we should auto hide these depending on output from getCompilers lll: { desc: 'Compiles LLL source code.', args: [{ name: 'sourceString', type: 'String', desc: 'The LLL source code.' }, { name: 'callback', type: 'Function', optional: true, desc: 'Watch callback' }] }, solidity: { desc: 'Compiles solidity source code', args: [{ name: 'sourceString', type: 'String', desc: 'The solidity source code.' }, { name: 'callback', type: 'Function', optional: true, desc: 'Watch callback' }], }, serpent: { desc: 'Compiles serpent source code', args: [{ name: 'sourceString', type: 'String', desc: 'The serpent source code.' }, { name: 'callback', type: 'Function', optional: true, desc: 'Watch callback' }] } }, namereg: { desc: 'Returns GlobalRegistrar object.' } }, db: { putString: { desc: 'Store a string in the local leveldb database.', args: [{ name: 'db', type: 'String', desc: 'The database to store to.' }, { name: 'key', type: 'String', desc: 'The name of the store.' }, { name: 'value', type: 'String', desc: 'The string value to store.' }] }, getString: { desc: 'Retrieve a string from the local leveldb database. (db, key)', args: [{ name: 'db', type: 'String', desc: 'The database string name to retrieve from.' }, { name: 'key', type: 'String', desc: 'The name of the store.' }] }, putHex: { desc: 'Store binary data in the local leveldb database. (db, key, value)', args: [{ name: 'db', type: 'String', desc: 'The database to store to.' }, { name: 'key', type: 'String', desc: 'The name of the store.' }, { name: 'value', type: 'String', desc: 'The HEX string to store.' }] }, getHex: { desc: 'Retrieve binary data from the local leveldb database. (db, key)', args: [{ name: 'db', type: 'String', desc: 'The database string name to retrieve from.' }, { name: 'key', type: 'String', desc: 'The name of the store.' }] } } } }; function jsSuggestionsContainerStyle(suggestionsCount) { return { marginVertical: 1, marginHorizontal: 0, keyboardShouldPersistTaps: true, //height: Math.min(150, (56 * suggestionsCount)), backgroundColor: "white", borderRadius: 5, keyboardShouldPersistTaps: true }; } var jsSuggestionContainerStyle = { paddingLeft: 16, backgroundColor: "white" }; var jsSubContainerStyle = { //height: 56, paddingTop: 9, borderBottomWidth: 1, borderBottomColor: "#0000001f" }; var jsValueStyle = { fontSize: 14, fontFamily: "font", color: "#000000de" }; var jsBoldValueStyle = { fontSize: 14, fontFamily: "font", color: "#000000de", fontWeight: "bold" }; var jsDescriptionStyle = { marginTop: 1.5, paddingBottom: 9, fontSize: 14, fontFamily: "font", color: "#838c93de" }; var messages = []; console = (function (old) { return { log: function (text) { old.log(text); var message = { type: 'log', message: JSON.stringify(text) }; messages.push(message); context.messages.push(message); }, info: function (text) { old.info(text); context.messages.push({ type: 'info', message: JSON.stringify(text) }); }, warn: function (text) { old.warn(text); context.messages.push({ type: 'warn', message: JSON.stringify(text) }); }, error: function (text) { old.error(text); context.messages.push({ type: 'error', message: JSON.stringify(text) }); } }; }(console)); if (!String.prototype.startsWith) { String.prototype.startsWith = function (searchString, position) { position = position || 0; return this.substr(position, searchString.length) === searchString; }; } function matchSubString(array, string) { var matched = []; for (var i = 0; i < array.length; i++) { var item = array[i]; if (item.toLowerCase().startsWith(string.toLowerCase())) { matched.push(item); } } return matched; } function cleanCode(code) { // remove comments var commentsRegex = /\/\*.+?\*\/|\/\/.*/g; code = code.replace(commentsRegex, ""); // replace string literals var literalsRegex = /\"(?:\\\\\"|[^\"])*?\"/g; code = code.replace(literalsRegex, '""'); var literalsRegex = /\'(?:\\\\\'|[^\'])*?\'/g; code = code.replace(literalsRegex, '""'); return code } function createObjectSuggestion(name, docInfo, code, parameterNumber) { var title = name; if (docInfo.args) { title += "("; for (var i = 0; i < docInfo.args.length; i++) { var argument = docInfo.args[i]; var argumentText = (i > 0 ? ", " : "") + (parameterNumber === i ? "*" + argument.name + "*" : argument.name); if (argument.optional) { argumentText = "[" + argumentText + "]"; } title += argumentText; } title += ")"; } if (!docInfo.desc) { name += "."; } else if (docInfo.args) { name += "("; if (docInfo.args.length == 0) { name += ")"; } } var suggestion = { title: title, desc: docInfo.desc }; if (code != null) { suggestion.pressValue = code + name; } return suggestion; } var lastMessage = null; function getLastForm(code) { var codeLength = code.length; var form = ''; var level = 0; var index = codeLength - 1; while (index >= 0) { var char = code[index]; if (level == 0 && (char == '(' || char == ',')) { break; } if (char == ')') { level--; } if (char == '(') { level++; } form = char + form; index--; } return form; } function getLastLevel(code) { var codeLength = code.length; var form = ''; var index = codeLength - 1; var nested = false; var level = 0; while (index >= 0) { var char = code[index]; if (char == ')') { level--; nested = true; } if (char == '(') { level++; if (level == 0) { nested = false; } if (level <= 0) { form = "argument" + form; index--; continue; } } if ((level == 1 && char == ',') || level == 2) { break; } if (!nested || level > 0) { form = char + form; } index--; } if (form.indexOf("(") < 0) { var parts = form.split(','); form = parts[parts.length - 1]; } return form; } function getPartialSuggestions(doc, fullCode, code) { var suggestions = []; var functionParts = code.split("("); var objectParts = code.split(/[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/); var index = 0; var suggestedFunction = ''; while (index < objectParts.length) { var part = objectParts[index]; if (part != "desc" && part != "args" && doc[part] != null) { doc = doc[part]; suggestedFunction += part + '.'; index++; } else { break; } } suggestedFunction = suggestedFunction.substring(0, suggestedFunction.length - 1) if (functionParts.length == 1) { // object suggestions if (index > objectParts.length - 1) { var suggestion = objectParts[objectParts.length - 1]; suggestions.push(createObjectSuggestion(suggestion, doc, fullCode.substring(0, fullCode.length - suggestion.length))); } else if (index === objectParts.length - 1) { var lastPart = objectParts[index]; var keys = Object.keys(doc); var matches = matchSubString(keys, lastPart); for (var i = 0; i < matches.length; i++) { var suggestion = matches[i]; if (suggestion == "desc" || suggestion == "args") { continue; } var docInfo = doc[suggestion]; if (docInfo != null) { suggestions.push(createObjectSuggestion(suggestion, docInfo, fullCode.substring(0, fullCode.length - lastPart.length))); } } } } else if (functionParts.length == 2) { // parameter suggestions var parameters = functionParts[1].split(","); if (doc.args && parameters.length <= doc.args.length && parameters[parameters.length - 1].indexOf(")") < 0) { var paramInfo = doc.args[parameters.length - 1]; var docInfo = doc; docInfo.desc = paramInfo.name + ": " + paramInfo.desc; suggestions.push(createObjectSuggestion(suggestedFunction, docInfo, null, parameters.length - 1)); } } console.log(suggestions); return suggestions; } function getJsSuggestions(code, context) { var suggestions = []; var doc = DOC_MAP; // TODO: what's /c / doing there ??? console.log(code); if (!code || code == "" || code == "c ") { code = ""; console.log("Last message: " + context.data); if (context.data != null) { suggestions.push({ title: 'Last command used:', desc: context.data, pressValue: context.data }); } var keys = Object.keys(doc); for (var i = 0; i < keys.length; i++) { var suggestion = keys[i]; var docInfo = doc[suggestion]; if (docInfo != null) { suggestions.push(createObjectSuggestion(suggestion, docInfo, "")); } } } else { // TODO: what's /c / doing there ??? if (code.startsWith("c ")) { code = code.substring(2); } if (context.data != null && (typeof context.data === 'string' || context.data instanceof String) && context.data.startsWith(code)) { suggestions.unshift({ title: 'Last command used:', desc: context.data, pressValue: context.data }); } var originalCode = code; code = cleanCode(code); var levelCode = getLastLevel(code); var code = getLastForm(levelCode); if (levelCode != code) { suggestions = getPartialSuggestions(doc, originalCode, levelCode); } console.log("Final code: " + code); console.log("Level code: " + levelCode); suggestions = suggestions.concat(getPartialSuggestions(doc, originalCode, code)); } return suggestions; } function createMarkupText(text) { var parts = []; var index = 0; var currentText = ''; var isBold = false; while (index < text.length) { var char = text[index]; if (char == '*') { if (currentText != '') { parts.push( status.components.text( {style: isBold ? jsBoldValueStyle : jsValueStyle}, currentText ) ); currentText = ''; } isBold = !isBold; } else { currentText += char; } index++; } if (currentText != '') { parts.push( status.components.text( {style: isBold ? jsBoldValueStyle : jsValueStyle}, currentText ) ); } console.log(parts); return parts; } function jsSuggestions(params, context) { var suggestions = getJsSuggestions(params.code, context); var sugestionsMarkup = []; for (var i = 0; i < suggestions.length; i++) { var suggestion = suggestions[i]; if (suggestion.title.indexOf('*') >= 0) { suggestion.title = createMarkupText(suggestion.title); } var suggestionMarkup = status.components.view(jsSuggestionContainerStyle, [status.components.view(jsSubContainerStyle, [ status.components.text({style: jsValueStyle}, suggestion.title), status.components.text({style: jsDescriptionStyle}, suggestion.desc) ])]); if (suggestion.pressValue) { suggestionMarkup = status.components.touchable({ onPress: [status.events.SET_VALUE, suggestion.pressValue] }, suggestionMarkup); } sugestionsMarkup.push(suggestionMarkup); } if (sugestionsMarkup.length > 0) { var view = status.components.scrollView(jsSuggestionsContainerStyle(sugestionsMarkup.length), sugestionsMarkup ); return {markup: view}; } } function jsHandler(params, context) { var result = { err: null, data: null, messages: [] }; messages = []; try { result.data = JSON.stringify(eval(params.code)); localStorage.set(params.code); } catch (e) { result.err = e; } result.messages = messages; return result; } function suggestionsContainerStyle(suggestionsCount) { return { marginVertical: 1, marginHorizontal: 0, keyboardShouldPersistTaps: true, height: Math.min(150, (56 * suggestionsCount)), backgroundColor: "white", borderRadius: 5, flexGrow: 1 }; } var suggestionContainerStyle = { paddingLeft: 16, backgroundColor: "white" }; var suggestionSubContainerStyle = { height: 56, borderBottomWidth: 1, borderBottomColor: "#0000001f" }; var valueStyle = { marginTop: 9, fontSize: 14, fontFamily: "font", color: "#000000de" }; var descriptionStyle = { marginTop: 1.5, fontSize: 14, fontFamily: "font", color: "#838c93de" }; function startsWith(str1, str2) { // String.startsWith(...) doesn't work in otto return str1.lastIndexOf(str2, 0) == 0 && str1 != str2; } function phoneSuggestions(params, context) { var ph, suggestions; if (!params.phone || params.phone == "") { ph = context.suggestions; } else { ph = context.suggestions.filter(function (phone) { return startsWith(phone.number, params.phone); }); } if (ph.length == 0) { return; } suggestions = ph.map(function (phone) { return status.components.touchable( {onPress: [status.events.SET_COMMAND_ARGUMENT, [0, phone.number]]}, status.components.view(suggestionContainerStyle, [status.components.view(suggestionSubContainerStyle, [ status.components.text( {style: valueStyle}, phone.number ), status.components.text( {style: descriptionStyle}, phone.description ) ])]) ); }); var view = status.components.scrollView( suggestionsContainerStyle(ph.length), suggestions ); return {markup: view}; } var phoneConfig = { name: "phone", registeredOnly: true, icon: "phone_white", color: "#5bb2a2", title: I18n.t('phone_title'), description: I18n.t('phone_description'), sequentialParams: true, validator: function (params) { return { validationHandler: "phone", parameters: [params.phone] }; }, params: [{ name: "phone", type: status.types.PHONE, suggestions: phoneSuggestions, placeholder: I18n.t('phone_placeholder') }] }; status.response(phoneConfig); status.command(phoneConfig); var faucets = [ /*{ name: "Ethereum Ropsten Faucet", url: "http://faucet.ropsten.be:3001" },*/ { name: "Status Testnet Faucet", url: "http://46.101.129.137:3001", } ]; function faucetSuggestions(params) { var suggestions = faucets.map(function (entry) { return status.components.touchable( {onPress: [status.events.SET_COMMAND_ARGUMENT, [0, entry.url]]}, status.components.view( suggestionContainerStyle, [status.components.view( suggestionSubContainerStyle, [ status.components.text( {style: valueStyle}, entry.name ), status.components.text( {style: descriptionStyle}, entry.url ) ] )] ) ); }); var view = status.components.scrollView( suggestionsContainerStyle(faucets.length), suggestions ); return {markup: view}; } status.command({ name: "faucet", title: I18n.t('faucet_title'), description: I18n.t('faucet_description'), color: "#7099e6", registeredOnly: true, params: [{ name: "url", type: status.types.TEXT, suggestions: faucetSuggestions, placeholder: I18n.t('faucet_placeholder') }], preview: function (params) { return { markup: status.components.text( {}, params.url ) }; }, shortPreview: function (params) { return { markup: status.components.text( {}, I18n.t('faucet_title') + ": " + params.url ) }; }, validator: function (params, context) { var f = faucets.map(function (entry) { return entry.url; }); if (f.indexOf(params.url) == -1) { var error = status.components.validationMessage( I18n.t('faucet_incorrect_title'), I18n.t('faucet_incorrect_description') ); return {markup: error}; } } }); function debugSuggestions(params) { var suggestions = ["On", "Off"].map(function (entry) { return status.components.touchable( {onPress: [status.events.SET_COMMAND_ARGUMENT, [0, entry]]}, status.components.view( suggestionContainerStyle, [status.components.view( suggestionSubContainerStyle, [ status.components.text( {style: valueStyle}, entry ) ] )] ) ); }); var view = status.components.scrollView( suggestionsContainerStyle(faucets.length), suggestions ); return {markup: view}; } status.command({ name: "debug", title: I18n.t('debug_mode_title'), description: I18n.t('debug_mode_description'), color: "#7099e6", registeredOnly: true, params: [{ name: "mode", suggestions: debugSuggestions, type: status.types.TEXT }], preview: function (params) { return { markup: status.components.text( {}, I18n.t('debug_mode_title') + ": " + params.mode ) }; }, shortPreview: function (params) { return { markup: status.components.text( {}, I18n.t('debug_mode_title') + ": " + params.mode ) }; } }); status.command({ name: "browse", title: "Browser", registeredOnly: true, description: "Open web browser", params: [{ name: "url", placeholder: "URL", type: status.types.TEXT }], onSend: function (params, context) { var url = params.url; if (!/^[a-zA-Z-_]+:/.test(url)) { url = 'http://' + url; } return { title: "Browser", dynamicTitle: true, markup: status.components.bridgedWebView(url) }; } }); // status.command({ // name: "help", // title: "Help", // description: "Request help from Console", // color: "#7099e6", // params: [{ // name: "query", // type: status.types.TEXT // }] // }); status.response({ name: "confirmation-code", color: "#7099e6", description: I18n.t('confirm_description'), sequentialParams: true, params: [{ name: "code", type: status.types.NUMBER }], validator: function (params) { if (!/^[\d]{4}$/.test(params.code)) { var error = status.components.validationMessage( I18n.t('confirm_validation_title'), I18n.t('confirm_validation_description') ); return {markup: error}; } } }); status.response({ name: "password", color: "#7099e6", description: I18n.t('password_description'), icon: "lock_white", sequentialParams: true, params: [ { name: "password", type: status.types.PASSWORD, placeholder: I18n.t('password_placeholder'), hidden: true }, { name: "password-confirmation", type: status.types.PASSWORD, placeholder: I18n.t('password_placeholder2'), hidden: true } ], validator: function (params, context) { if (!params.hasOwnProperty("password-confirmation") || params["password-confirmation"].length === 0) { if (params.password === null || params.password.length < 6) { var error = status.components.validationMessage( I18n.t('password_validation_title'), I18n.t('password_error') ); return {markup: error}; } } else { if (params.password !== params["password-confirmation"]) { var error = status.components.validationMessage( I18n.t('password_validation_title'), I18n.t('password_error1') ); return {markup: error}; } } }, preview: function (params, context) { var style = { marginTop: 5, marginHorizontal: 0, fontSize: 14, color: "black" }; if (context.platform == "ios") { style.fontSize = 8; style.marginTop = 10; style.marginBottom = 2; style.letterSpacing = 1; } return {markup: status.components.text({style: style}, "●●●●●●●●●●")}; } }); status.registerFunction("message-suggestions", function (params, context) { return jsSuggestions({code: params.message}, context); }); status.registerFunction("message-handler", function (params, context) { return jsHandler({code: params.message}, context); });